Forge
pythonb1bb0b24
1from __future__ import annotations
2
3import logging
4import smtplib
5from email.message import EmailMessage
6
7import httpx
8
9from open_agent_registry.config import settings
10
11logger = logging.getLogger(__name__)
12
13ClaimChannel = str # "email" | "telegram" | "totp"
14
15
16def normalize_email(email: str) -> str:
17 value = email.strip().lower()
18 if "@" not in value or len(value) > 320:
19 raise ValueError("Invalid email")
20 return value
21
22
23def send_email_code(to_email: str, agent_name: str, code: str) -> bool:
24 """Send claim code via SMTP. Returns True if sent, False if SMTP not configured."""
25 if not settings.smtp_host:
26 return False
27
28 message = EmailMessage()
29 message["Subject"] = f"Open Agent Registry — claim code for {agent_name}"
30 message["From"] = settings.smtp_from or settings.smtp_user or "noreply@open-agent-registry.local"
31 message["To"] = to_email
32 message.set_content(
33 f"Your verification code for agent «{agent_name}»:\n\n{code}\n\n"
34 f"If you did not request this, ignore this message."
35 )
36
37 with smtplib.SMTP(settings.smtp_host, settings.smtp_port, timeout=30) as smtp:
38 if settings.smtp_use_tls:
39 smtp.starttls()
40 if settings.smtp_user and settings.smtp_password:
41 smtp.login(settings.smtp_user, settings.smtp_password)
42 smtp.send_message(message)
43 return True
44
45
46def send_telegram_code(chat_id: str, agent_name: str, code: str) -> bool:
47 if not settings.telegram_bot_token:
48 return False
49
50 text = (
51 f"Open Agent Registry\n"
52 f"Claim code for «{agent_name}»: `{code}`\n"
53 f"(enter on claim page)"
54 )
55 url = f"https://api.telegram.org/bot{settings.telegram_bot_token}/sendMessage"
56 response = httpx.post(
57 url,
58 json={"chat_id": chat_id, "text": text, "parse_mode": "Markdown"},
59 timeout=30.0,
60 )
61 response.raise_for_status()
62 payload = response.json()
63 if not payload.get("ok"):
64 raise RuntimeError(payload.get("description", "Telegram API error"))
65 return True
66
View only · write via MCP/CIDE