fix(auth): machine_token não exige email+senha no socket + case-insensitive
continuous-integration/webhook Deploy concluído (VPS4)

Bugs corrigidos:

1. Condição bloqueante: 'if (email && password && token.includes("-"))' fazia
   o machine_token ser ignorado se o client conectasse só com o token (sem
   email/senha). A conexão caía para o check de JWT, falhava e era rejeitada.
   Agora o machine_token é verificado sempre que o token contém hífens —
   email+senha são opcionais (validados se presentes, ignorados se ausentes).

2. Comparação de email case-sensitive: 'device.email === email' falhava
   se houver diferença de maiúsculas/minúsculas entre o cadastro e o config
   do client. Corrigido para .toLowerCase() em ambos os lados.

3. Log de autenticação: emite mensagem clara no console quando machine_token
   é aceito, incluindo nome da clínica e do PC, facilitando diagnóstico.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Deploy Agent
2026-05-31 09:06:29 +02:00
parent 42fc1fc90e
commit 526f3f2eae
+25 -16
View File
@@ -751,29 +751,38 @@ io.use(async (socket, next) => {
return next(); // Token válido, prosseguir
}
// 1.5 Verificar se é um machine_token (usado pelo novo app desktop 1.2.4+)
if (email && password && token.includes('-')) {
// 1.5 Verificar se é um machine_token (UUID com hífens — app desktop)
// O machine_token é credencial suficiente por si só (UUID único gerado pelo servidor).
// Se email+senha também forem enviados, valida os dois para compatibilidade.
if (token.includes('-')) {
try {
const device = await db.get(`SELECT * FROM clinics_devices WHERE machine_token = $1`, [token]);
if (device && device.email === email && device.is_active) {
const { verifyPassword } = require('./auth');
const validPassword = await verifyPassword(password, device.password_hash);
if (validPassword) {
console.log(`✅ Conexão Socket.IO autorizada via machine_token - IP: ${socket.handshake.address}`);
socket.clientType = 'sensor';
socket.user = { role: 'client_device', clinicId: device.id, clinicName: device.clinic_name, pcName: device.pc_name };
// Atualiza o último IP e data
await db.run(`UPDATE clinics_devices SET last_ip = $1 WHERE id = $2`, [socket.handshake.address, device.id]);
return next(); // Credenciais válidas
if (device && device.is_active) {
// Se email e senha foram enviados, valida-os também (case-insensitive no email)
if (email && password) {
const emailMatch = device.email.toLowerCase() === email.trim().toLowerCase();
if (!emailMatch) {
console.log(`❌ [machine_token] Email não confere para device id=${device.id}`);
return next(new Error('Authentication error: Invalid machine_token or credentials'));
}
const { verifyPassword } = require('./auth');
const validPassword = await verifyPassword(password, device.password_hash);
if (!validPassword) {
console.log(`❌ [machine_token] Senha inválida para device id=${device.id}`);
return next(new Error('Authentication error: Invalid machine_token or credentials'));
}
}
// machine_token válido (com ou sem email+senha)
console.log(`✅ [machine_token] Conexão autorizada — Clínica: ${device.clinic_name} PC: ${device.pc_name}`);
socket.clientType = 'sensor';
socket.user = { role: 'client_device', clinicId: device.id, clinicName: device.clinic_name, pcName: device.pc_name };
await db.run(`UPDATE clinics_devices SET last_ip = $1 WHERE id = $2`, [socket.handshake.address, device.id]);
return next();
}
// Token com hífens mas não é machine_token → pode ser JWT, deixa prosseguir
} catch (e) {
console.error('Erro ao validar machine_token no socket:', e);
}
console.log(`❌ Conexão Socket.IO rejeitada (Machine Token inválido) - IP: ${socket.handshake.address}`);
return next(new Error('Authentication error: Invalid machine_token or credentials'));
}
// 2. Se não for a API_KEY, tentar validar como JWT (Painel Web ou Novo App Desktop)