297 lines
9.2 KiB
JavaScript
297 lines
9.2 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const db = require('../database');
|
|
const { verifyPassword, generateToken, hashPassword, authenticateToken } = require('../auth');
|
|
|
|
// ================================================================
|
|
// POST /api/auth/login - Login
|
|
// ================================================================
|
|
|
|
router.post('/login', async (req, res) => {
|
|
try {
|
|
const { username, password } = req.body;
|
|
|
|
if (!username || !password) {
|
|
return res.status(400).json({
|
|
error: 'Usuário e senha são obrigatórios'
|
|
});
|
|
}
|
|
|
|
// Buscar usuário
|
|
const user = await db.get(
|
|
'SELECT * FROM users WHERE username = $1 OR email = $2',
|
|
[username, username]
|
|
);
|
|
|
|
if (!user) {
|
|
return res.status(401).json({
|
|
error: 'Usuário ou senha inválidos'
|
|
});
|
|
}
|
|
|
|
// Verificar senha
|
|
const validPassword = await verifyPassword(password, user.password_hash);
|
|
|
|
if (!validPassword) {
|
|
return res.status(401).json({
|
|
error: 'Usuário ou senha inválidos'
|
|
});
|
|
}
|
|
|
|
// Gerar token
|
|
const token = generateToken(user);
|
|
|
|
// Resposta
|
|
res.json({
|
|
success: true,
|
|
token: token,
|
|
user: {
|
|
id: user.id,
|
|
username: user.username,
|
|
email: user.email,
|
|
clinic_name: user.clinic_name,
|
|
pc_name: user.pc_name,
|
|
is_admin: user.is_admin
|
|
}
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Erro no login:', error);
|
|
res.status(500).json({ error: 'Erro interno do servidor' });
|
|
}
|
|
});
|
|
|
|
// ================================================================
|
|
// GET /api/auth/verify - Verificar token
|
|
// ================================================================
|
|
|
|
router.get('/verify', async (req, res) => {
|
|
try {
|
|
const authHeader = req.headers['authorization'];
|
|
const token = authHeader && authHeader.split(' ')[1];
|
|
|
|
if (!token) {
|
|
return res.status(401).json({ error: 'Token não fornecido' });
|
|
}
|
|
|
|
const jwt = require('jsonwebtoken');
|
|
const decoded = jwt.verify(token, require('../auth').JWT_SECRET);
|
|
|
|
const user = await db.get('SELECT * FROM users WHERE id = $1', [decoded.id]);
|
|
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'Usuário não encontrado' });
|
|
}
|
|
|
|
res.json({
|
|
valid: true,
|
|
user: {
|
|
id: user.id,
|
|
username: user.username,
|
|
email: user.email,
|
|
clinic_name: user.clinic_name,
|
|
pc_name: user.pc_name,
|
|
is_admin: user.is_admin
|
|
}
|
|
});
|
|
|
|
} catch (error) {
|
|
res.status(401).json({ error: 'Token inválido' });
|
|
}
|
|
});
|
|
|
|
// ================================================================
|
|
// POST /api/auth/logout - Logout
|
|
// ================================================================
|
|
|
|
router.post('/logout', (req, res) => {
|
|
res.json({
|
|
success: true,
|
|
message: 'Logout realizado com sucesso'
|
|
});
|
|
});
|
|
|
|
// ================================================================
|
|
// POST /api/auth/create-user - Criar usuário (admin only)
|
|
// ================================================================
|
|
|
|
router.post('/create-user', authenticateToken, async (req, res) => {
|
|
try {
|
|
if (!req.user.is_admin) {
|
|
return res.status(403).json({ error: 'Apenas administradores podem criar usuários' });
|
|
}
|
|
|
|
const { username, email, password, clinic_name, pc_name, is_admin } = req.body;
|
|
|
|
if (!username || !email || !password) {
|
|
return res.status(400).json({
|
|
error: 'Username, email e senha são obrigatórios'
|
|
});
|
|
}
|
|
|
|
// Verificar se usuário já existe
|
|
const existing = await db.get(
|
|
'SELECT * FROM users WHERE username = $1 OR email = $2',
|
|
[username, email]
|
|
);
|
|
|
|
if (existing) {
|
|
return res.status(409).json({
|
|
error: 'Usuário ou email já cadastrado'
|
|
});
|
|
}
|
|
|
|
// Hash da senha
|
|
const passwordHash = await hashPassword(password);
|
|
|
|
// Criar usuário
|
|
const result = await db.run(
|
|
`INSERT INTO users (username, email, password_hash, clinic_name, pc_name, is_admin, created_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP) RETURNING id`,
|
|
[username, email, passwordHash, clinic_name || null, pc_name || null, !!is_admin]
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Usuário criado com sucesso',
|
|
userId: result.lastID
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Erro ao criar usuário:', error);
|
|
res.status(500).json({ error: 'Erro interno do servidor' });
|
|
}
|
|
});
|
|
|
|
// ================================================================
|
|
// GERENCIAMENTO DE USUÁRIOS/CLÍNICAS (ADMIN)
|
|
// ================================================================
|
|
|
|
router.get('/users', authenticateToken, async (req, res) => {
|
|
try {
|
|
if (!req.user.is_admin) {
|
|
return res.status(403).json({ error: 'Acesso negado' });
|
|
}
|
|
const users = await db.all('SELECT id, username, email, clinic_name, pc_name, is_admin, created_at FROM users ORDER BY created_at DESC');
|
|
res.json({ success: true, users });
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Erro ao buscar usuários' });
|
|
}
|
|
});
|
|
|
|
router.delete('/users/:id', authenticateToken, async (req, res) => {
|
|
try {
|
|
if (!req.user.is_admin) {
|
|
return res.status(403).json({ error: 'Acesso negado' });
|
|
}
|
|
const userId = req.params.id;
|
|
if (parseInt(userId) === req.user.id) {
|
|
return res.status(400).json({ error: 'Não é possível excluir o próprio usuário admin' });
|
|
}
|
|
await db.run('DELETE FROM users WHERE id = $1', [userId]);
|
|
res.json({ success: true, message: 'Usuário excluído com sucesso' });
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Erro ao excluir usuário' });
|
|
}
|
|
});
|
|
|
|
router.post('/users/:id/token', authenticateToken, async (req, res) => {
|
|
try {
|
|
if (!req.user.is_admin) {
|
|
return res.status(403).json({ error: 'Acesso negado' });
|
|
}
|
|
const user = await db.get('SELECT * FROM users WHERE id = $1', [req.params.id]);
|
|
if (!user) return res.status(404).json({ error: 'Usuário não encontrado' });
|
|
|
|
// Gera um token com duração longa para uso no desktop (ex: 3650 dias = ~10 anos)
|
|
const token = generateToken(user, '3650d');
|
|
res.json({ success: true, token });
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Erro ao gerar token' });
|
|
}
|
|
});
|
|
|
|
// ================================================================
|
|
// PUT /api/auth/update-credentials - Alterar usuário/senha
|
|
// ================================================================
|
|
|
|
router.put('/update-credentials', authenticateToken, async (req, res) => {
|
|
try {
|
|
const { currentPassword, newUsername, newEmail, newPassword } = req.body;
|
|
const userId = req.user.id;
|
|
|
|
if (!currentPassword) {
|
|
return res.status(400).json({ error: 'A senha atual é obrigatória' });
|
|
}
|
|
|
|
if (!newUsername && !newEmail && !newPassword) {
|
|
return res.status(400).json({ error: 'Nenhum dado novo foi fornecido para atualização' });
|
|
}
|
|
|
|
// Buscar usuário atual para verificar a senha
|
|
const user = await db.get('SELECT * FROM users WHERE id = $1', [userId]);
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'Usuário não encontrado' });
|
|
}
|
|
|
|
// Verificar senha atual
|
|
const validPassword = await verifyPassword(currentPassword, user.password_hash);
|
|
if (!validPassword) {
|
|
return res.status(401).json({ error: 'A senha atual está incorreta' });
|
|
}
|
|
|
|
let finalUsername = user.username;
|
|
let finalEmail = user.email;
|
|
let finalPasswordHash = user.password_hash;
|
|
|
|
// Verificar e aplicar novo username se fornecido
|
|
if (newUsername && newUsername !== user.username) {
|
|
const existing = await db.get('SELECT * FROM users WHERE username = $1 AND id != $2', [newUsername, userId]);
|
|
if (existing) {
|
|
return res.status(409).json({ error: 'Este nome de usuário já está em uso' });
|
|
}
|
|
finalUsername = newUsername;
|
|
}
|
|
|
|
// Verificar e aplicar novo e-mail se fornecido
|
|
if (newEmail && newEmail !== user.email) {
|
|
const existing = await db.get('SELECT * FROM users WHERE email = $1 AND id != $2', [newEmail, userId]);
|
|
if (existing) {
|
|
return res.status(409).json({ error: 'Este e-mail já está em uso' });
|
|
}
|
|
finalEmail = newEmail;
|
|
}
|
|
|
|
// Verificar e aplicar nova senha se fornecido
|
|
if (newPassword) {
|
|
if (newPassword.length < 4) {
|
|
return res.status(400).json({ error: 'A nova senha deve ter pelo menos 4 caracteres' });
|
|
}
|
|
finalPasswordHash = await hashPassword(newPassword);
|
|
}
|
|
|
|
// Atualizar no banco de dados
|
|
await db.run(
|
|
'UPDATE users SET username = $1, email = $2, password_hash = $3 WHERE id = $4',
|
|
[finalUsername, finalEmail, finalPasswordHash, userId]
|
|
);
|
|
|
|
// Gerar novo token pois o username ou e-mail podem ter mudado
|
|
const updatedUser = { id: userId, username: finalUsername, email: finalEmail, is_admin: user.is_admin };
|
|
const newToken = generateToken(updatedUser);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Credenciais atualizadas com sucesso',
|
|
token: newToken,
|
|
user: updatedUser
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Erro ao atualizar credenciais:', error);
|
|
res.status(500).json({ error: 'Erro interno do servidor' });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|