Implement email-based 2FA authentication for Telegram bot with Oracle integration fixes
This commit adds a complete email authentication flow for the Telegram bot, allowing users to login with email + password instead of web app linking codes. Includes critical bug fixes for Oracle integration. **New Features:** - Email-based 2FA authentication with 6-digit codes sent via SMTP - Backend endpoints: verify-email and login-with-email - ConversationHandler for email authentication flow in Telegram bot - Session token verification to prevent user ID spoofing - Rate limiting (5 attempts per 5 minutes) - Email code expiry (5 minutes) with automatic cleanup **Bug Fixes:** - Fixed Oracle column name: ACTIV → INACTIV (with inverted logic) - Fixed Oracle password verification: verificautilizator returns checksum, not user_id - Fixed username case sensitivity: Oracle usernames must be uppercase - Fixed SMTP connection: use start_tls parameter instead of manual STARTTLS - Added middleware exclusions for public email auth endpoints **Backend Changes:** - Added verify-email endpoint (public) in telegram.py - Added login-with-email endpoint (public) with rate limiting and session verification - Updated middleware exclusions in main.py and auth_middleware_wrapper.py - Added AUTH_SESSION_SECRET configuration for session token signing **Telegram Bot Changes:** - New modules: app/auth/email_auth.py, app/bot/email_handlers.py - New utilities: app/utils/email_service.py (SMTP email sending) - Updated handlers.py: ignore callbacks handled by ConversationHandler - Updated menus.py: show Login button for unauthenticated users - Updated API client: verify_email() and login_with_email() methods - Database: email_auth_codes table with cleanup task **Configuration:** - Added SMTP configuration to telegram-bot .env.example - Added AUTH_SESSION_SECRET to backend .env.example - Updated .gitignore: exclude temporary files (*.pid, *.checksum, test scripts) **Dependencies:** - Added aiosmtplib for async SMTP email sending 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,12 @@ from telegram.ext import (
|
||||
)
|
||||
|
||||
# Import database initialization
|
||||
from app.db import init_database, cleanup_expired_codes, cleanup_expired_sessions
|
||||
from app.db import (
|
||||
init_database,
|
||||
cleanup_expired_codes,
|
||||
cleanup_expired_sessions,
|
||||
cleanup_expired_email_codes
|
||||
)
|
||||
|
||||
# Import bot handlers
|
||||
from app.bot.handlers import (
|
||||
@@ -61,6 +66,9 @@ from app.bot.handlers import (
|
||||
error_handler
|
||||
)
|
||||
|
||||
# Import email authentication handler
|
||||
from app.bot.email_handlers import email_login_handler
|
||||
|
||||
# Import internal API
|
||||
from app.internal_api import internal_api
|
||||
|
||||
@@ -93,6 +101,9 @@ def create_telegram_application() -> Application:
|
||||
# Create application
|
||||
application = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
|
||||
|
||||
# Register email authentication conversation handler (must be before other handlers)
|
||||
application.add_handler(email_login_handler)
|
||||
|
||||
# Register essential command handlers
|
||||
application.add_handler(CommandHandler("start", start_command))
|
||||
application.add_handler(CommandHandler("menu", menu_command))
|
||||
@@ -186,7 +197,8 @@ async def startup():
|
||||
logger.info("Cleaning up expired data...")
|
||||
expired_codes = await cleanup_expired_codes()
|
||||
expired_sessions = await cleanup_expired_sessions()
|
||||
logger.info(f"✅ Cleanup complete: {expired_codes} codes, {expired_sessions} sessions removed")
|
||||
expired_email_codes = await cleanup_expired_email_codes()
|
||||
logger.info(f"✅ Cleanup complete: {expired_codes} codes, {expired_sessions} sessions, {expired_email_codes} email codes removed")
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Cleanup failed (non-critical): {e}")
|
||||
|
||||
@@ -204,7 +216,7 @@ async def shutdown():
|
||||
async def scheduled_cleanup():
|
||||
"""
|
||||
Background task to periodically clean up expired data.
|
||||
Runs every hour to remove expired auth codes and sessions.
|
||||
Runs every hour to remove expired auth codes, sessions, and email codes.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
@@ -212,7 +224,8 @@ async def scheduled_cleanup():
|
||||
logger.info("🧹 Running scheduled cleanup...")
|
||||
expired_codes = await cleanup_expired_codes()
|
||||
expired_sessions = await cleanup_expired_sessions()
|
||||
logger.info(f"✅ Scheduled cleanup: {expired_codes} codes, {expired_sessions} sessions removed")
|
||||
expired_email_codes = await cleanup_expired_email_codes()
|
||||
logger.info(f"✅ Scheduled cleanup: {expired_codes} codes, {expired_sessions} sessions, {expired_email_codes} email codes removed")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error in scheduled cleanup: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user