chore: add automated database backup service and tighten backend security
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m56s
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m56s
- Added `databack/mysql-backup` service to the production docker-compose Swarm stack, scheduling a daily 02:55 AM cron backup of the database with a 3-day local retention policy. - Fixed a critical race condition in the backend JWT authentication middleware where an invalid token returning 401 could crash the response flow if the route executed before the defensive checks caught it. - Added strict undefined defensive checks to the `getUserById` endpoint and RBAC middleware to gracefully reject requests that somehow bypass the token parser. - Updated `GEMINI.md` technical documentation to fully match the real codebase logic. - Fixed UX rule to prevent `manager` role from seeing Funnels or Origins tabs in the sidebar. - Blocked `agent` role from modifying their own 'fullName' string in the Profile UI.
This commit is contained in:
@@ -136,14 +136,17 @@ const authenticateToken = async (req, res, next) => {
|
||||
|
||||
if (!token) return res.status(401).json({ error: 'Token não fornecido.' });
|
||||
|
||||
jwt.verify(token, JWT_SECRET, (err, user) => {
|
||||
if (err) return res.status(401).json({ error: 'Token inválido ou expirado.' });
|
||||
try {
|
||||
const user = jwt.verify(token, JWT_SECRET);
|
||||
req.user = user;
|
||||
next();
|
||||
});
|
||||
} catch (err) {
|
||||
return res.status(401).json({ error: 'Token inválido ou expirado.' });
|
||||
}
|
||||
};
|
||||
|
||||
const requireRole = (roles) => (req, res, next) => {
|
||||
if (!req.user || !req.user.role) return res.status(401).json({ error: 'Não autenticado.' });
|
||||
if (!roles.includes(req.user.role)) return res.status(403).json({ error: 'Acesso negado. Você não tem permissão para realizar esta ação.' });
|
||||
next();
|
||||
};
|
||||
@@ -457,7 +460,7 @@ apiRouter.get('/users/:idOrSlug', async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query('SELECT * FROM users WHERE id = ? OR slug = ?', [req.params.idOrSlug, req.params.idOrSlug]);
|
||||
if (!rows || rows.length === 0) return res.status(404).json({ error: 'Not found' });
|
||||
if (!req.user) return res.status(401).json({ error: 'Não autenticado' });
|
||||
if (!req.user || !req.user.role) return res.status(401).json({ error: 'Não autenticado' });
|
||||
|
||||
if (req.user.role !== 'super_admin' && rows[0].tenant_id !== req.user.tenant_id) {
|
||||
return res.status(403).json({ error: 'Acesso negado.' });
|
||||
|
||||
Reference in New Issue
Block a user