fix(login): elimina fallback legacy y exige employee_id + PIN correcto
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

- auth_bp.py: ahora login requiere employee_id. Si el PIN no coincide con
  el empleado seleccionado, devuelve 401. Ya no escanea todos los empleados
  ni permite entrar como otro usuario con el mismo PIN.

Esto evita que al elegir un usuario se entre como mecanico solo porque
comparten PIN.
This commit is contained in:
2026-06-30 17:23:39 +00:00
parent 1ca056ad0f
commit 76dfa2adff

View File

@@ -90,53 +90,26 @@ def login_pin():
matched_employee = None matched_employee = None
if employee_id: if not employee_id:
# Secure flow: user selected an employee, verify only that PIN. _record_attempt(device_id, False)
cur.execute(""" cur.close()
SELECT e.id, e.name, e.pin, e.role, e.branch_id, e.max_discount_pct conn.close()
FROM employees e return jsonify({'error': 'Empleado no seleccionado'}), 400
WHERE e.id = %s AND e.is_active = true AND e.pin IS NOT NULL
""", (employee_id,))
emp = cur.fetchone()
if emp:
emp_id, emp_name, emp_pin_hash, emp_role, emp_branch, emp_discount = emp
if emp_pin_hash and bcrypt.checkpw(pin.encode(), emp_pin_hash.encode()):
matched_employee = {
'id': emp_id, 'name': emp_name, 'role': emp_role,
'branch_id': emp_branch, 'max_discount_pct': float(emp_discount) if emp_discount else 0
}
if not matched_employee: # Verify the PIN only for the selected employee.
# Legacy fallback: scan active employees (kept for old clients without employee_id) cur.execute("""
if device_branch_id: SELECT e.id, e.name, e.pin, e.role, e.branch_id, e.max_discount_pct
cur.execute(""" FROM employees e
SELECT e.id, e.name, e.pin, e.role, e.branch_id, e.max_discount_pct WHERE e.id = %s AND e.is_active = true AND e.pin IS NOT NULL
FROM employees e """, (employee_id,))
WHERE e.is_active = true AND e.pin IS NOT NULL AND e.branch_id = %s emp = cur.fetchone()
""", (device_branch_id,)) if emp:
for emp in cur.fetchall(): emp_id, emp_name, emp_pin_hash, emp_role, emp_branch, emp_discount = emp
emp_id, emp_name, emp_pin_hash, emp_role, emp_branch, emp_discount = emp if emp_pin_hash and bcrypt.checkpw(pin.encode(), emp_pin_hash.encode()):
if emp_pin_hash and bcrypt.checkpw(pin.encode(), emp_pin_hash.encode()): matched_employee = {
matched_employee = { 'id': emp_id, 'name': emp_name, 'role': emp_role,
'id': emp_id, 'name': emp_name, 'role': emp_role, 'branch_id': emp_branch, 'max_discount_pct': float(emp_discount) if emp_discount else 0
'branch_id': emp_branch, 'max_discount_pct': float(emp_discount) if emp_discount else 0 }
}
break
if not matched_employee:
cur.execute("""
SELECT e.id, e.name, e.pin, e.role, e.branch_id, e.max_discount_pct
FROM employees e
WHERE e.is_active = true AND e.pin IS NOT NULL
""")
for emp in cur.fetchall():
emp_id, emp_name, emp_pin_hash, emp_role, emp_branch, emp_discount = emp
if emp_pin_hash and bcrypt.checkpw(pin.encode(), emp_pin_hash.encode()):
matched_employee = {
'id': emp_id, 'name': emp_name, 'role': emp_role,
'branch_id': emp_branch, 'max_discount_pct': float(emp_discount) if emp_discount else 0
}
break
if not matched_employee: if not matched_employee:
_record_attempt(device_id, False) _record_attempt(device_id, False)