From 54552df79560ce6baefd83ef82ac70d4562722db Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 14 Apr 2026 03:04:24 +0200 Subject: [PATCH] Stop leaking e.message to clients across all routes 88 occurrences of res.status(500).json({ error: e.message }) (or err.message) swept to generic 'Request failed'. Server-side console.error / logger.error calls are untouched, so the full detail still lands in logs and Grafana. Covers: admin, adminConfig, adminMilestones, chartReview, documents, encounters, hospitalCourse, hpi, learningAdmin, learningAI, learningHub, logs, memories, milestones, oidc, refine, sessions, sickVisit, soap, userPreferences, wellVisit. Also extends .gitignore to exclude .env.backup-* files. --- .gitignore | 2 ++ src/routes/admin.js | 22 ++++++++-------- src/routes/adminConfig.js | 48 +++++++++++++++++------------------ src/routes/adminMilestones.js | 12 ++++----- src/routes/chartReview.js | 2 +- src/routes/documents.js | 8 +++--- src/routes/encounters.js | 8 +++--- src/routes/hospitalCourse.js | 6 ++--- src/routes/hpi.js | 4 +-- src/routes/learningAI.js | 12 ++++----- src/routes/learningAdmin.js | 4 +-- src/routes/learningHub.js | 6 ++--- src/routes/logs.js | 8 +++--- src/routes/memories.js | 12 ++++----- src/routes/milestones.js | 6 ++--- src/routes/oidc.js | 4 +-- src/routes/refine.js | 6 ++--- src/routes/sessions.js | 6 ++--- src/routes/sickVisit.js | 2 +- src/routes/soap.js | 2 +- src/routes/userPreferences.js | 6 ++--- src/routes/wellVisit.js | 4 +-- 22 files changed, 96 insertions(+), 94 deletions(-) diff --git a/.gitignore b/.gitignore index 385bc14..651dcbc 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ android/.idea/ *.keystore *.jks public/models/ +.env.backup-* +*.env.backup* diff --git a/src/routes/admin.js b/src/routes/admin.js index 77f98d1..30c5e20 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -23,7 +23,7 @@ router.get('/users', async function(req, res) { [] ); res.json({ success: true, users: users }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -45,7 +45,7 @@ router.get('/users/:id', async function(req, res) { user.last_login = lastLogin ? lastLogin.timestamp : null; res.json({ success: true, user: user }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -61,7 +61,7 @@ router.post('/users/:id/verify', async function(req, res) { logger.audit(req.user.id, 'admin_verify_user', 'Verified user: ' + user.email, req, { category: 'admin' }); res.json({ success: true, message: user.email + ' verified' }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -84,7 +84,7 @@ router.post('/users/:id/disable', async function(req, res) { logger.audit(req.user.id, 'admin_disable_user', 'Disabled user: ' + user.email, req, { category: 'admin' }); res.json({ success: true, message: user.email + ' disabled' }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -100,7 +100,7 @@ router.post('/users/:id/enable', async function(req, res) { logger.audit(req.user.id, 'admin_enable_user', 'Enabled user: ' + user.email, req, { category: 'admin' }); res.json({ success: true, message: user.email + ' enabled' }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -128,7 +128,7 @@ router.post('/users/:id/role', async function(req, res) { logger.audit(req.user.id, 'admin_change_role', 'Set ' + user.email + ' role to ' + role, req, { category: 'admin' }); res.json({ success: true, message: user.email + ' is now ' + role }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -151,7 +151,7 @@ router.delete('/users/:id', async function(req, res) { logger.audit(req.user.id, 'admin_delete_user', 'Deleted user: ' + user.email + ' (' + user.name + ')', req, { category: 'admin' }); res.json({ success: true, message: user.email + ' deleted' }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -171,7 +171,7 @@ router.post('/users/:id/reset-password', async function(req, res) { logger.audit(req.user.id, 'admin_reset_password', 'Reset password for: ' + user.email, req, { category: 'admin' }); res.json({ success: true, message: 'Password reset for ' + user.email }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -187,7 +187,7 @@ router.post('/settings/registration', async function(req, res) { logger.audit(req.user.id, 'admin_toggle_registration', 'Registration ' + (enabled ? 'enabled' : 'disabled'), req, { category: 'admin' }); res.json({ success: true, registrationEnabled: enabled, message: 'Registration ' + (enabled ? 'enabled' : 'disabled') }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -211,7 +211,7 @@ router.get('/settings', async function(req, res) { todayApiCalls: todayApiCount ? parseInt(todayApiCount.count) : 0 } }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -235,7 +235,7 @@ router.get('/logs/all', async function(req, res) { var logs = await db.all(sql, params); res.json({ success: true, logs: logs }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); module.exports = router; diff --git a/src/routes/adminConfig.js b/src/routes/adminConfig.js index dfae7b6..3bf82b8 100644 --- a/src/routes/adminConfig.js +++ b/src/routes/adminConfig.js @@ -23,7 +23,7 @@ router.get('/config/announcement', async function(req, res) { text: text || '', type: type || 'info' }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); router.use(adminMiddleware); @@ -45,7 +45,7 @@ router.get('/config', async function(req, res) { } }); res.json({ success: true, config: rows }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST send test email ─────────────────────────────────────────────────── @@ -76,7 +76,7 @@ router.post('/config/test-email', async function(req, res) { var ok = await sendEmail(to, '[TEST] ' + subject, html); res.json({ success: ok, message: ok ? 'Test email sent to ' + to : 'SMTP not configured' }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── GET prompt list (for editor UI) ─────────────────────────────────────── @@ -93,7 +93,7 @@ router.get('/config/prompts', async function(req, res) { p.dbKey = dbKey; }); res.json({ success: true, prompts: prompts }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST reset a prompt to hardcoded default ────────────────────────────── @@ -112,7 +112,7 @@ router.post('/config/prompts/:key/reset', async function(req, res) { logger.audit(req.user.id, 'admin_config_reset', 'Reset prompt to default: ' + key, req, { category: 'admin' }); res.json({ success: true, value: PROMPTS[key] }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST reset all non-prompt settings to defaults ────────────────────── @@ -138,7 +138,7 @@ router.post('/config/reset-defaults', async function(req, res) { } logger.audit(req.user.id, 'admin_config_reset_all', 'Reset all settings to defaults', req, { category: 'admin' }); res.json({ success: true, message: 'Settings reset to defaults (SMTP and custom models preserved)' }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── GET SMTP status ────────────────────────────────────────────────────── @@ -158,7 +158,7 @@ router.get('/config/smtp/status', async function(req, res) { from: from, source: process.env.SMTP_HOST ? 'env' : (host ? 'database' : 'none') }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── PUT update SMTP settings ───────────────────────────────────────────── @@ -179,7 +179,7 @@ router.put('/config/smtp', async function(req, res) { logger.audit(req.user.id, 'admin_smtp_update', 'Updated SMTP settings', req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── DELETE SMTP settings (clear DB override, fall back to env) ─────────── @@ -191,7 +191,7 @@ router.delete('/config/smtp', async function(req, res) { } logger.audit(req.user.id, 'admin_smtp_clear', 'Cleared SMTP DB overrides', req, { category: 'admin' }); res.json({ success: true, message: 'SMTP DB settings cleared (env vars still apply if set)' }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -232,7 +232,7 @@ router.get('/config/models', async function(req, res) { defaultModel: defaultModel, litellmHint: activeProvider === 'litellm' }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── PUT toggle model enabled/disabled ──────────────────────────────────── @@ -254,7 +254,7 @@ router.put('/config/models/toggle', async function(req, res) { await db.setSetting('models.disabled', JSON.stringify(disabled)); logger.audit(req.user.id, 'admin_model_toggle', (enabled ? 'Enabled' : 'Disabled') + ' model: ' + modelId, req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── PUT set default model ───────────────────────────────────────────────── @@ -265,7 +265,7 @@ router.put('/config/models/default', async function(req, res) { await db.setSetting('models.default', modelId.trim()); logger.audit(req.user.id, 'admin_model_default', 'Set default model: ' + modelId, req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST add custom model (manual entry) ───────────────────────────────── @@ -301,7 +301,7 @@ router.post('/config/models/custom', async function(req, res) { await db.setSetting('models.custom', JSON.stringify(custom)); logger.audit(req.user.id, existing ? 'admin_model_update' : 'admin_model_add', (existing ? 'Updated' : 'Added') + ' custom model: ' + trimmedId, req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── DELETE custom model ─────────────────────────────────────────────────── @@ -315,7 +315,7 @@ router.delete('/config/models/custom/:modelId(*)', async function(req, res) { await db.setSetting('models.custom', JSON.stringify(custom)); logger.audit(req.user.id, 'admin_model_delete', 'Removed custom model: ' + modelId, req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST clear all custom/discovered models ─────────────────────────────── @@ -326,7 +326,7 @@ router.post('/config/models/clear-all', async function(req, res) { await db.setSetting('models.default', ''); logger.audit(req.user.id, 'admin_models_clear_all', 'Cleared all custom models and disabled list', req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── GET discover models from provider API ───────────────────────────────── @@ -341,7 +341,7 @@ router.get('/config/models/discover', async function(req, res) { }); } res.json({ success: true, models: discovered, count: discovered.length }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST add discovered model to custom list ────────────────────────────── @@ -366,7 +366,7 @@ router.post('/config/models/add-discovered', async function(req, res) { await db.setSetting('models.custom', JSON.stringify(custom)); logger.audit(req.user.id, 'admin_model_discover_add', 'Added discovered model: ' + trimmedId, req, { category: 'admin' }); res.json({ success: true, id: trimmedId }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST test a model with a simple prompt ──────────────────────────────── @@ -430,7 +430,7 @@ router.get('/config/tts', async function(req, res) { elevenlabs: ['pNInz6obpgDQGcFmaJgB'] } }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── GET discover TTS voices from provider ──────────────────────────────── @@ -513,7 +513,7 @@ router.get('/config/tts/discover', async function(req, res) { }); } res.json({ success: true, provider: provider, voices: discovered, count: discovered.length }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST test TTS — returns base64 audio ───────────────────────────────── @@ -614,7 +614,7 @@ router.get('/config/stt', async function(req, res) { local: ['tiny', 'base', 'small', 'medium', 'large'] } }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── GET discover STT models from provider ──────────────────────────────── @@ -695,7 +695,7 @@ router.get('/config/stt/discover', async function(req, res) { }); } res.json({ success: true, provider: provider, models: discovered, count: discovered.length }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST test STT — accepts base64 audio, returns transcription ─────────── @@ -797,7 +797,7 @@ router.get('/config/embeddings', async function(req, res) { { id: 'text-embedding-ada-002', name: 'OpenAI text-embedding-ada-002', dims: 1536, tag: 'OPENAI' } ] }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── GET discover embedding models from provider ─────────────────────────── @@ -872,7 +872,7 @@ router.get('/config/embeddings/discover', async function(req, res) { }); } res.json({ success: true, provider: provider, models: discovered, count: discovered.length }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── POST test embedding ─────────────────────────────────────────────────── @@ -930,7 +930,7 @@ router.put('/config/:key(*)', async function(req, res) { logger.audit(req.user.id, 'admin_config_update', 'Updated config: ' + key, req, { category: 'admin' }); res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); module.exports = router; diff --git a/src/routes/adminMilestones.js b/src/routes/adminMilestones.js index 8378f45..7784521 100644 --- a/src/routes/adminMilestones.js +++ b/src/routes/adminMilestones.js @@ -20,7 +20,7 @@ router.get('/milestones', adminMiddleware, async (req, res) => { const result = await db.query(query, params); res.json({ success: true, milestones: result.rows }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -40,7 +40,7 @@ router.get('/milestones/meta', adminMiddleware, async (req, res) => { domains: domains.rows.map(r => r.domain) }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -62,7 +62,7 @@ router.post('/milestones', adminMiddleware, async (req, res) => { res.json({ success: true, milestone: result.rows[0] }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -90,7 +90,7 @@ router.put('/milestones/:id', adminMiddleware, async (req, res) => { res.json({ success: true, milestone: result.rows[0] }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -110,7 +110,7 @@ router.delete('/milestones/:id', adminMiddleware, async (req, res) => { res.json({ success: true, message: 'Milestone deleted' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -142,7 +142,7 @@ router.post('/milestones/bulk-import', adminMiddleware, async (req, res) => { res.json({ success: true, imported }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/chartReview.js b/src/routes/chartReview.js index bf3e815..2cb6378 100644 --- a/src/routes/chartReview.js +++ b/src/routes/chartReview.js @@ -66,7 +66,7 @@ router.post('/generate-chart-review', authMiddleware, async (req, res) => { res.json({ success: true, review: result.content, model: result.model }); logger.audit(req.user.id, 'generate_chart_review', 'Generated chart review', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/documents.js b/src/routes/documents.js index bf164fd..6bca42e 100644 --- a/src/routes/documents.js +++ b/src/routes/documents.js @@ -70,7 +70,7 @@ router.get('/documents', async function(req, res) { [req.user.id] ); res.json({ success: true, documents: rows, s3_configured: true }); - } catch (e) { logger.error('GET /documents', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('GET /documents', e.message); res.status(500).json({ error: 'Could not list documents' }); } }); // ── POST upload document ─────────────────────────────────────────────── @@ -107,7 +107,7 @@ router.post('/documents/upload', upload.single('file'), async function(req, res) res.json({ success: true, id: result.lastInsertRowid, filename: req.file.originalname }); logger.audit(req.user.id, 'document_upload', 'Uploaded: ' + (req.file ? req.file.originalname : 'unknown'), req, { category: 'documents' }); - } catch (e) { logger.error('POST /documents/upload', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('POST /documents/upload', e.message); res.status(500).json({ error: 'Upload failed' }); } }); // ── GET download document (presigned URL) ────────────────────────────── @@ -132,7 +132,7 @@ router.get('/documents/:id/download', async function(req, res) { res.json({ success: true, url: url }); logger.audit(req.user.id, 'document_download', 'Downloaded document ' + req.params.id, req, { category: 'documents' }); - } catch (e) { logger.error('GET /documents/:id/download', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('GET /documents/:id/download', e.message); res.status(500).json({ error: 'Download failed' }); } }); // ── DELETE document ──────────────────────────────────────────────────── @@ -158,7 +158,7 @@ router.delete('/documents/:id', async function(req, res) { await db.run('DELETE FROM user_documents WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]); res.json({ success: true }); logger.audit(req.user.id, 'document_delete', 'Deleted document ' + req.params.id, req, { category: 'documents' }); - } catch (e) { logger.error('DELETE /documents/:id', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('DELETE /documents/:id', e.message); res.status(500).json({ error: 'Delete failed' }); } }); module.exports = router; diff --git a/src/routes/encounters.js b/src/routes/encounters.js index ae39ebc..e8a0b83 100644 --- a/src/routes/encounters.js +++ b/src/routes/encounters.js @@ -18,7 +18,7 @@ router.get('/encounters/saved', async function(req, res) { [req.user.id] ); res.json({ success: true, encounters: rows }); - } catch (e) { logger.error('GET /encounters/saved', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('GET /encounters/saved', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── GET single saved encounter ─────────────────────────────────────────── @@ -31,7 +31,7 @@ router.get('/encounters/saved/:id', async function(req, res) { if (!row) return res.status(404).json({ error: 'Encounter not found or expired' }); logger.audit(req.user.id, 'encounter_load', 'Loaded encounter: ' + (row.label || 'unlabeled') + ' (id:' + req.params.id + ')', req, { category: 'clinical' }); res.json({ success: true, encounter: row }); - } catch (e) { logger.error('GET /encounters/saved/:id', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('GET /encounters/saved/:id', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── POST save/update encounter progress ───────────────────────────────── @@ -109,7 +109,7 @@ router.post('/encounters/saved', async function(req, res) { res.json({ success: true, id: result.lastInsertRowid }); logger.audit(req.user.id, 'encounter_save', 'Saved encounter: ' + (label || 'unlabeled'), req, { category: 'clinical' }); } - } catch (e) { logger.error('POST /encounters/saved', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('POST /encounters/saved', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── DELETE saved encounter ─────────────────────────────────────────────── @@ -122,7 +122,7 @@ router.delete('/encounters/saved/:id', async function(req, res) { if (result.changes === 0) return res.status(404).json({ error: 'Not found' }); res.json({ success: true }); logger.audit(req.user.id, 'encounter_delete', 'Deleted encounter ' + req.params.id, req, { category: 'clinical' }); - } catch (e) { logger.error('DELETE /encounters/saved/:id', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('DELETE /encounters/saved/:id', e.message); res.status(500).json({ error: 'Request failed' }); } }); module.exports = router; diff --git a/src/routes/hospitalCourse.js b/src/routes/hospitalCourse.js index 9d03380..e4de7a2 100644 --- a/src/routes/hospitalCourse.js +++ b/src/routes/hospitalCourse.js @@ -97,7 +97,7 @@ router.post('/generate-hospital-course', authMiddleware, async (req, res) => { }); logger.audit(req.user.id, 'generate_hospital_course', 'Generated hospital course', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -113,7 +113,7 @@ router.post('/hospital-course-clarify', authMiddleware, async (req, res) => { res.json({ success: true, questions: result.content, model: result.model }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -137,7 +137,7 @@ ${PROMPTS.refine.split('\n').slice(0, -1).join('\n')}` }, res.json({ success: true, hospitalCourse: result.content, model: result.model }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/hpi.js b/src/routes/hpi.js index 58af674..61b44a7 100644 --- a/src/routes/hpi.js +++ b/src/routes/hpi.js @@ -24,7 +24,7 @@ router.post('/generate-hpi-encounter', authMiddleware, async (req, res) => { res.json({ success: true, hpi: result.content, model: result.model }); logger.audit(req.user.id, 'generate_hpi_encounter', 'Generated HPI from encounter', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -47,7 +47,7 @@ router.post('/generate-hpi-dictation', authMiddleware, async (req, res) => { res.json({ success: true, hpi: result.content, model: result.model }); logger.audit(req.user.id, 'generate_hpi_dictation', 'Generated HPI from dictation', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/learningAI.js b/src/routes/learningAI.js index 918acd1..6ddd698 100644 --- a/src/routes/learningAI.js +++ b/src/routes/learningAI.js @@ -325,7 +325,7 @@ router.post('/ai-generate', upload.array('files', 10), async function(req, res) } catch (err) { console.error('[LearningAI]', err.message); - res.status(500).json({ error: err.message || 'Generation failed' }); + res.status(500).json({ error: 'Generation failed' }); } }); @@ -355,7 +355,7 @@ Return ONLY the refined HTML body (same structure, no JSON wrapper, no markdown res.json({ success: true, refined, model: result.model }); } catch (err) { console.error('[LearningAI]', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -435,7 +435,7 @@ router.get('/webdav-browse', async function(req, res) { res.json({ success: true, path: browsePath, parentPath, items }); } catch (err) { console.error('[WebDAV]', err.message); - res.status(500).json({ error: 'WebDAV browse failed: ' + err.message }); + res.status(500).json({ error: 'WebDAV browse failed' }); } }); @@ -448,7 +448,7 @@ router.post('/webdav-path', async function(req, res) { await db.run('UPDATE users SET webdav_learning_path = ? WHERE id = ?', [wPath || null, req.user.id]); res.json({ success: true }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -701,7 +701,7 @@ router.post('/generate-pptx', async function(req, res) { } catch (err) { console.error('[PPTX]', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -728,7 +728,7 @@ router.post('/preview-slides', async function(req, res) { res.json({ success: true, css: css, slides: slides }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/learningAdmin.js b/src/routes/learningAdmin.js index bef6bfe..825eb30 100644 --- a/src/routes/learningAdmin.js +++ b/src/routes/learningAdmin.js @@ -391,7 +391,7 @@ router.post('/embeddings/generate', async function(req, res) { } catch (err) { console.error('[LearningAdmin]', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -412,7 +412,7 @@ router.get('/embeddings/status', async function(req, res) { dimensions: parseInt(process.env.EMBEDDING_DIMENSIONS) || 768 }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/learningHub.js b/src/routes/learningHub.js index db60ade..cef0d43 100644 --- a/src/routes/learningHub.js +++ b/src/routes/learningHub.js @@ -139,7 +139,7 @@ router.get('/content/:slug/slides', async function(req, res) { if (slides.length === 0) slides.push(html); res.json({ success: true, css: css, slides: slides }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // ============================================================ @@ -282,7 +282,7 @@ router.get('/search/semantic', async function(req, res) { } catch (err) { console.error('[LearningHub] Semantic search error:', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -362,7 +362,7 @@ router.get('/search/hybrid', async function(req, res) { } catch (err) { console.error('[LearningHub] Hybrid search error:', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/logs.js b/src/routes/logs.js index aa719cc..e8cd7ee 100644 --- a/src/routes/logs.js +++ b/src/routes/logs.js @@ -8,28 +8,28 @@ router.get('/logs/usage', authMiddleware, async function(req, res) { var days = parseInt(req.query.days) || 30; var summary = await logger.getUsageSummary(req.user.id, days); res.json({ success: true, summary: summary, period: days + ' days' }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); router.get('/logs/audit', authMiddleware, async function(req, res) { try { var logs = await logger.getAuditLogs(req.user.id, parseInt(req.query.limit) || 50); res.json({ success: true, logs: logs }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); router.get('/logs/api', authMiddleware, async function(req, res) { try { var logs = await logger.getApiLogs(req.user.id, parseInt(req.query.limit) || 50); res.json({ success: true, logs: logs }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); router.get('/logs/access', authMiddleware, async function(req, res) { try { var logs = await logger.getAccessLogs(req.user.id, parseInt(req.query.limit) || 50); res.json({ success: true, logs: logs }); - } catch (err) { res.status(500).json({ error: err.message }); } + } catch (err) { res.status(500).json({ error: 'Request failed' }); } }); // Client-side error receiver — no auth required (sendBeacon can't send auth headers) diff --git a/src/routes/memories.js b/src/routes/memories.js index 7169640..adc98ae 100644 --- a/src/routes/memories.js +++ b/src/routes/memories.js @@ -24,7 +24,7 @@ router.get('/memories', async function(req, res) { [req.user.id] ); res.json({ success: true, memories: rows }); - } catch (e) { logger.error('GET /memories', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('GET /memories', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── POST create memory ─────────────────────────────────────────────────── @@ -44,7 +44,7 @@ router.post('/memories', async function(req, res) { [req.user.id, cat, name.trim().substring(0, 100), content.trim().substring(0, 5000)] ); res.json({ success: true, id: result.lastInsertRowid }); - } catch (e) { logger.error('POST /memories', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('POST /memories', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── PUT update memory ──────────────────────────────────────────────────── @@ -63,7 +63,7 @@ router.put('/memories/:id', async function(req, res) { ] ); res.json({ success: true }); - } catch (e) { logger.error('PUT /memories/:id', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('PUT /memories/:id', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── DELETE memory ──────────────────────────────────────────────────────── @@ -71,7 +71,7 @@ router.delete('/memories/:id', async function(req, res) { try { await db.run('DELETE FROM user_memories WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]); res.json({ success: true }); - } catch (e) { logger.error('DELETE /memories/:id', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('DELETE /memories/:id', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── GET memories as prompt context (for AI generation) ────────────────── @@ -119,7 +119,7 @@ router.get('/memories/context', async function(req, res) { }); } res.json({ success: true, context: context.trim() }); - } catch (e) { logger.error('GET /memories/context', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('GET /memories/context', e.message); res.status(500).json({ error: 'Request failed' }); } }); // ── POST auto-save correction (Dragon-like learning) ────────────────── @@ -156,7 +156,7 @@ router.post('/memories/correction', async function(req, res) { [req.user.id, cat, name, content] ); res.json({ success: true }); - } catch (e) { logger.error('POST /memories/correction', e.message); res.status(500).json({ error: e.message }); } + } catch (e) { logger.error('POST /memories/correction', e.message); res.status(500).json({ error: 'Request failed' }); } }); module.exports = router; diff --git a/src/routes/milestones.js b/src/routes/milestones.js index bdd072a..69b5e5f 100644 --- a/src/routes/milestones.js +++ b/src/routes/milestones.js @@ -27,7 +27,7 @@ router.get('/milestones-data', authMiddleware, async (req, res) => { res.json({ success: true, milestones: grouped }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -71,7 +71,7 @@ router.post('/generate-milestone-narrative', authMiddleware, async (req, res) => }); logger.audit(req.user.id, 'generate_milestone_narrative', 'Generated milestone narrative', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -89,7 +89,7 @@ router.post('/generate-milestone-summary', authMiddleware, async (req, res) => { res.json({ success: true, summary: result.content, model: result.model }); logger.audit(req.user.id, 'generate_milestone_summary', 'Generated milestone summary', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/oidc.js b/src/routes/oidc.js index 547c796..bcead4d 100644 --- a/src/routes/oidc.js +++ b/src/routes/oidc.js @@ -245,7 +245,7 @@ router.get('/oidc/config', authMiddleware, adminMiddleware, async function(req, config['oidc.client_secret'] = '••••••••' + config['oidc.client_secret'].slice(-4); } res.json({ success: true, config: config }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); // ── Admin: PUT update OIDC config ─────────────────────────────────────── @@ -264,7 +264,7 @@ router.put('/oidc/config', authMiddleware, adminMiddleware, async function(req, } res.json({ success: true }); - } catch (e) { res.status(500).json({ error: e.message }); } + } catch (e) { res.status(500).json({ error: 'Request failed' }); } }); module.exports = router; diff --git a/src/routes/refine.js b/src/routes/refine.js index 1732181..b812d98 100644 --- a/src/routes/refine.js +++ b/src/routes/refine.js @@ -34,7 +34,7 @@ router.post('/refine', authMiddleware, async function(req, res) { res.json({ success: true, refined: result.content, model: result.model }); logger.audit(req.user.id, 'refine_document', 'Refined document', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -54,7 +54,7 @@ router.post('/shorten', authMiddleware, async function(req, res) { res.json({ success: true, shortened: result.content, model: result.model }); logger.audit(req.user.id, 'shorten_document', 'Shortened document', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -75,7 +75,7 @@ router.post('/clarify', authMiddleware, async function(req, res) { res.json({ success: true, questions: result.content, model: result.model }); logger.audit(req.user.id, 'clarify_document', 'Generated clarification questions', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/sessions.js b/src/routes/sessions.js index 5070ad9..0488a62 100644 --- a/src/routes/sessions.js +++ b/src/routes/sessions.js @@ -14,7 +14,7 @@ router.get('/', async function(req, res) { ); res.json({ success: true, sessions: sessions, currentSessionId: req.sessionId || null }); } catch (e) { - res.status(500).json({ error: e.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -31,7 +31,7 @@ router.delete('/:id', async function(req, res) { if (result.changes === 0) return res.status(404).json({ error: 'Session not found' }); res.json({ success: true }); } catch (e) { - res.status(500).json({ error: e.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -45,7 +45,7 @@ router.delete('/', async function(req, res) { ); res.json({ success: true, revoked: result.changes }); } catch (e) { - res.status(500).json({ error: e.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/sickVisit.js b/src/routes/sickVisit.js index 1bf3d13..46815f7 100644 --- a/src/routes/sickVisit.js +++ b/src/routes/sickVisit.js @@ -67,7 +67,7 @@ router.post('/sick-visit/note', authMiddleware, async function(req, res) { logger.audit(req.user.id, 'generate_sick_visit', 'Generated sick visit note', req, { category: 'clinical' }); } catch (e) { logger.error('[SickVisit] Note generation failed', e.message); - res.status(500).json({ error: e.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/soap.js b/src/routes/soap.js index 1263aac..e4a6e27 100644 --- a/src/routes/soap.js +++ b/src/routes/soap.js @@ -32,7 +32,7 @@ router.post('/generate-soap', authMiddleware, async (req, res) => { res.json({ success: true, soap: result.content, model: result.model }); logger.audit(req.user.id, 'generate_soap', 'Generated SOAP note', req, { category: 'clinical' }); } catch (err) { - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/userPreferences.js b/src/routes/userPreferences.js index 3d29ff5..1556d9f 100644 --- a/src/routes/userPreferences.js +++ b/src/routes/userPreferences.js @@ -20,7 +20,7 @@ router.get('/preferences', async function(req, res) { }); } catch (err) { console.error('[Preferences]', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -37,7 +37,7 @@ router.post('/preferences', async function(req, res) { res.json({ success: true }); } catch (err) { console.error('[Preferences]', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -150,7 +150,7 @@ router.get('/preferences/options', async function(req, res) { } catch (err) { console.error('[Preferences]', err.message); - res.status(500).json({ error: err.message }); + res.status(500).json({ error: 'Request failed' }); } }); diff --git a/src/routes/wellVisit.js b/src/routes/wellVisit.js index f0622b3..b20f2bc 100644 --- a/src/routes/wellVisit.js +++ b/src/routes/wellVisit.js @@ -126,7 +126,7 @@ router.post('/well-visit/shadess', authMiddleware, async function(req, res) { logger.audit(req.user.id, 'generate_shadess', 'Generated SSHADESS assessment', req, { category: 'clinical' }); } catch (e) { logger.error('[WellVisit] SHADESS generation failed', e.message); - res.status(500).json({ error: e.message }); + res.status(500).json({ error: 'Request failed' }); } }); @@ -228,7 +228,7 @@ router.post('/well-visit/note', authMiddleware, async function(req, res) { logger.audit(req.user.id, 'generate_well_visit', 'Generated well visit note', req, { category: 'clinical' }); } catch (e) { logger.error('[WellVisit] Note generation failed', e.message); - res.status(500).json({ error: e.message }); + res.status(500).json({ error: 'Request failed' }); } });