135 lines
4.5 KiB
Python
135 lines
4.5 KiB
Python
"""Send notification emails via Postfix (SMTP)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import smtplib
|
|
from email.message import EmailMessage
|
|
|
|
ROOT_NOTIFY_EMAIL = os.getenv("DESK_ROOT_NOTIFY_EMAIL", "admin@ligbox.com.br")
|
|
DESK_PUBLIC_URL = os.getenv("DESK_PUBLIC_URL", "https://desk.ligbox.com.br")
|
|
MAIL_FROM = os.getenv("DESK_MAIL_FROM", "ligbox-ops@ligbox.com.br")
|
|
SMTP_HOST = os.getenv("DESK_SMTP_HOST", "10.10.10.122")
|
|
SMTP_PORT = int(os.getenv("DESK_SMTP_PORT", "25"))
|
|
|
|
|
|
def send_email(to: str, subject: str, body: str) -> bool:
|
|
to = (to or "").strip()
|
|
if not to:
|
|
return False
|
|
msg = EmailMessage()
|
|
msg["From"] = MAIL_FROM
|
|
msg["To"] = to
|
|
msg["Subject"] = subject
|
|
msg.set_content(body)
|
|
try:
|
|
with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=15) as smtp:
|
|
smtp.send_message(msg)
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def notify_root_registration_pending(email: str, request_id: int) -> bool:
|
|
body = (
|
|
f"Novo pedido de cadastro Ligbox Ops Desk\n\n"
|
|
f"E-mail: {email}\n"
|
|
f"ID: {request_id}\n\n"
|
|
f"Aprovar em: {DESK_PUBLIC_URL}/\n"
|
|
f"(Menu Mensagens)\n"
|
|
)
|
|
return send_email(ROOT_NOTIFY_EMAIL, f"[Ligbox Ops] Pedido de cadastro: {email}", body)
|
|
|
|
|
|
def notify_candidate_approved(email: str, activation_url: str, role: str) -> bool:
|
|
body = (
|
|
f"Seu pedido de acesso ao Ligbox Ops Desk foi APROVADO.\n\n"
|
|
f"Perfil atribuído: {role}\n\n"
|
|
f"Ative sua conta (complete 2 de 3 fatores: e-mail, telefone ou app 2FA):\n{activation_url}\n\n"
|
|
f"Este link expira em 48 horas.\n"
|
|
)
|
|
return send_email(email, "[Ligbox Ops] Conta aprovada — ative agora", body)
|
|
|
|
|
|
def notify_candidate_rejected(email: str, reason: str | None = None) -> bool:
|
|
body = "Seu pedido de acesso ao Ligbox Ops Desk foi rejeitado."
|
|
if reason:
|
|
body += f"\n\nMotivo: {reason}"
|
|
return send_email(email, "[Ligbox Ops] Pedido de cadastro rejeitado", body)
|
|
|
|
|
|
def send_otp_email(email: str, code: str, purpose: str) -> bool:
|
|
body = (
|
|
f"Código de verificação Ligbox Ops Desk\n\n"
|
|
f"Finalidade: {purpose}\n"
|
|
f"Código: {code}\n\n"
|
|
f"Válido por 10 minutos.\n"
|
|
)
|
|
return send_email(email, f"[Ligbox Ops] Código: {code}", body)
|
|
|
|
|
|
def mask_email(email: str) -> str:
|
|
email = (email or "").strip()
|
|
if "@" not in email:
|
|
return email
|
|
local, domain = email.split("@", 1)
|
|
if len(local) <= 2:
|
|
masked_local = local[0] + "***"
|
|
else:
|
|
masked_local = local[0] + "***" + local[-1]
|
|
return f"{masked_local}@{domain}"
|
|
|
|
|
|
def notify_mfa_recovery_started(username: str, email: str) -> bool:
|
|
body = (
|
|
f"Recuperação de 2FA iniciada no Ligbox Ops Desk\n\n"
|
|
f"Utilizador: {username}\n"
|
|
f"E-mail de verificação: {email}\n\n"
|
|
f"Se não foi você, contacte o root imediatamente.\n"
|
|
)
|
|
return send_email(
|
|
ROOT_NOTIFY_EMAIL,
|
|
f"[Ligbox Ops] Recuperação 2FA: {username}",
|
|
body,
|
|
)
|
|
|
|
|
|
def notify_mfa_recovery_completed(username: str) -> bool:
|
|
body = (
|
|
f"Recuperação de 2FA concluída no Ligbox Ops Desk\n\n"
|
|
f"Utilizador: {username}\n"
|
|
f"Novo autenticador configurado e códigos de backup gerados.\n"
|
|
)
|
|
return send_email(
|
|
ROOT_NOTIFY_EMAIL,
|
|
f"[Ligbox Ops] 2FA reconfigurado: {username}",
|
|
body,
|
|
)
|
|
|
|
|
|
def notify_admin_2fa_reset(target_username: str, target_email: str, admin_username: str) -> bool:
|
|
body = (
|
|
f"O administrador {admin_username} resetou o 2FA da conta:\n\n"
|
|
f"Utilizador: {target_username}\n"
|
|
f"E-mail: {target_email}\n\n"
|
|
f"O utilizador pode entrar só com senha e reconfigurar o autenticador em:\n"
|
|
f"{DESK_PUBLIC_URL}/login.html\n"
|
|
f"(Perdi acesso ao autenticador)\n"
|
|
)
|
|
send_email(target_email, "[Ligbox Ops] 2FA resetado pelo administrador", body)
|
|
return send_email(
|
|
ROOT_NOTIFY_EMAIL,
|
|
f"[Ligbox Ops] Admin resetou 2FA: {target_username}",
|
|
body,
|
|
)
|
|
|
|
|
|
def send_backup_codes_email(email: str, codes: list[str]) -> bool:
|
|
lines = "\n".join(f" • {c}" for c in codes)
|
|
body = (
|
|
f"Códigos de backup — Ligbox Ops Desk\n\n"
|
|
f"Guarde estes códigos em local seguro. Cada código só pode ser usado uma vez.\n\n"
|
|
f"{lines}\n\n"
|
|
f"Use-os no login se perder acesso ao aplicativo autenticador.\n"
|
|
)
|
|
return send_email(email, "[Ligbox Ops] Códigos de backup 2FA", body)
|