security fixes

This commit is contained in:
null 2026-05-28 03:59:35 -05:00
parent d3f2a921bf
commit 8cab248959
5 changed files with 44 additions and 58 deletions

64
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "bill-tracker",
"version": "0.28.1",
"version": "0.28.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bill-tracker",
"version": "0.28.1",
"version": "0.28.3",
"license": "ISC",
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.1.2",
@ -32,8 +32,8 @@
"express": "^4.18.2",
"express-rate-limit": "^8.4.1",
"lucide-react": "^0.456.0",
"node-cron": "^3.0.3",
"nodemailer": "^6.9.14",
"node-cron": "^4.2.1",
"nodemailer": "^8.0.9",
"openid-client": "^5.7.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@ -2770,21 +2770,6 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.15.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
"integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@ -3571,14 +3556,14 @@
}
},
"node_modules/express": {
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"version": "4.22.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz",
"integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "~1.20.3",
"body-parser": "~1.20.5",
"content-disposition": "~0.5.4",
"content-type": "~1.0.4",
"cookie": "~0.7.1",
@ -3597,7 +3582,7 @@
"parseurl": "~1.3.3",
"path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
"qs": "~6.14.0",
"qs": "~6.15.1",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "~0.19.0",
@ -5364,13 +5349,10 @@
}
},
"node_modules/node-cron": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz",
"integrity": "sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz",
"integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==",
"license": "ISC",
"dependencies": {
"uuid": "8.3.2"
},
"engines": {
"node": ">=6.0.0"
}
@ -5383,9 +5365,9 @@
"license": "MIT"
},
"node_modules/nodemailer": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz",
"integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==",
"version": "8.0.9",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.9.tgz",
"integrity": "sha512-5ofa7BUN8+C+Hckh5V2GjeeOGRQBx0CJQA6KxrvuZfC8iU4/q7sLn8XrtEEhJkjV6HdyIiQs7Bba6bTao8JhkA==",
"license": "MIT-0",
"engines": {
"node": ">=6.0.0"
@ -5792,9 +5774,9 @@
}
},
"node_modules/qs": {
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"version": "6.15.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
"integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@ -7107,16 +7089,6 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View File

@ -37,8 +37,8 @@
"express": "^4.18.2",
"express-rate-limit": "^8.4.1",
"lucide-react": "^0.456.0",
"node-cron": "^3.0.3",
"nodemailer": "^6.9.14",
"node-cron": "^4.2.1",
"nodemailer": "^8.0.9",
"openid-client": "^5.7.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",

View File

@ -463,7 +463,7 @@ router.post('/check-updates', requireAuth, requireAdmin, async (req, res) => {
const result = await checkForUpdates(true);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message || 'Update check failed' });
res.status(500).json({ error: 'Update check failed' });
}
});

View File

@ -2,6 +2,7 @@ const express = require('express');
const router = express.Router();
const { getDb, rollbackMigration } = require('../db/database');
const { hashPassword } = require('../services/authService');
const { logAudit } = require('../services/auditService');
const {
createBackup,
deleteBackup,
@ -162,10 +163,18 @@ router.post('/users', async (req, res) => {
"INSERT INTO users (username, password_hash, role, first_login) VALUES (?, ?, 'user', 1)"
).run(username, hash);
res.status(201).json(
db.prepare('SELECT id, username, role, active, is_default_admin, must_change_password, first_login, created_at FROM users WHERE id = ?')
.get(result.lastInsertRowid)
);
const created = db.prepare(
'SELECT id, username, role, active, is_default_admin, must_change_password, first_login, created_at FROM users WHERE id = ?'
).get(result.lastInsertRowid);
logAudit({
user_id: req.user.id, action: 'admin.user.create',
entity_type: 'user', entity_id: created.id,
details: { created_username: username },
ip_address: req.ip, user_agent: req.get('user-agent'),
});
res.status(201).json(created);
});
// PUT /api/admin/users/:id/password
@ -182,11 +191,16 @@ router.put('/users/:id/password', async (req, res) => {
db.prepare("UPDATE users SET password_hash=?, must_change_password=1, updated_at=datetime('now') WHERE id=?")
.run(hash, req.params.id);
db.prepare('DELETE FROM sessions WHERE user_id = ?').run(req.params.id);
res.json({ success: true });
logAudit({
user_id: req.user.id, action: 'admin.password.reset',
entity_type: 'user', entity_id: Number(req.params.id),
details: { target_username: user.username },
ip_address: req.ip, user_agent: req.get('user-agent'),
});
// Import audit service
const { logAudit } = require('../services/auditService');
res.json({ success: true });
});
// PUT /api/admin/users/:id/role
// Promote/demote an existing user. Prevents removing the last admin or

View File

@ -73,7 +73,7 @@ router.get('/history', (req, res) => {
updated_at: updatedAt,
});
} catch (err) {
res.status(500).json({ error: err.message || 'Failed to read release history' });
res.status(500).json({ error: 'Failed to read release history' });
}
});
@ -84,7 +84,7 @@ router.get('/update-status', async (req, res) => {
try {
res.json(await checkForUpdates(false));
} catch (err) {
res.json({ current_version: pkg.version, latest_version: null, up_to_date: null, has_update: false, error: err.message });
res.json({ current_version: pkg.version, latest_version: null, up_to_date: null, has_update: false, error: 'Update check unavailable' });
}
});