Files
gh-christianlouis-dmarq/backend/app/api/api_v1/endpoints/imap.py
T
google-labs-jules[bot] 1831c1a079 🔒 security: move IMAP credentials to request body and fix CI/pylint issues
- Moved IMAP credentials from query parameters to the request body for the test-connection endpoint.
- Created missing `__init__.py` files across `backend/app/` to fix CI `ModuleNotFoundError`.
- Reformatted `setup.py` and `user.py` using `black` to pass lint checks.
- Addressed Pylint warnings in `imap.py` (unused arguments, lazy logging, exception chaining).

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-23 18:57:40 +00:00

120 lines
3.9 KiB
Python

import logging
from datetime import datetime
from typing import Any, Dict, Optional
from app.core.security import require_admin_auth
from app.services.imap_client import IMAPClient
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
from pydantic import BaseModel
router = APIRouter()
logger = logging.getLogger(__name__)
class IMAPTestRequest(BaseModel):
"""IMAP connection test request body"""
server: Optional[str] = None
port: int = 993
username: Optional[str] = None
password: Optional[str] = None
ssl: bool = True
@router.post("/test-connection")
async def test_imap_connection(
request: IMAPTestRequest,
_auth: dict = Depends(require_admin_auth),
) -> Dict[str, Any]:
"""
Test connection to an IMAP server and gather mailbox statistics
Security: Requires authentication (X-API-Key or Bearer token)
Credentials should be passed in request body
"""
imap_client = IMAPClient(
server=request.server,
port=request.port,
username=request.username,
password=request.password,
)
success, message, stats = imap_client.test_connection()
return {
"success": success,
"message": message,
"message_count": stats.get("message_count", 0),
"unread_count": stats.get("unread_count", 0),
"dmarc_count": stats.get("dmarc_count", 0),
"available_mailboxes": stats.get("available_mailboxes", []),
"timestamp": datetime.now().isoformat(),
}
@router.post("/fetch-reports")
async def fetch_imap_reports(
background_tasks: BackgroundTasks,
_auth: dict = Depends(require_admin_auth),
days: int = 7,
delete_emails: bool = False,
) -> Dict[str, Any]:
"""
Fetch DMARC reports from the configured IMAP mailbox
Security: Requires authentication (X-API-Key or Bearer token)
"""
# Security: Validate parameters
if days < 1 or days > 365:
raise HTTPException(status_code=400, detail="Days parameter must be between 1 and 365")
imap_client = IMAPClient(delete_emails=delete_emails)
# Run in background if it might take a while
if days > 14:
background_tasks.add_task(imap_client.fetch_reports, days)
return {
"success": True,
"message": f"Background task started to fetch {days} days of reports",
"timestamp": datetime.now().isoformat(),
}
# Otherwise run immediately
try:
results = imap_client.fetch_reports(days=days)
return {
"success": results["success"],
"processed_emails": results["processed"],
"reports_found": results["reports_found"],
"new_domains": results["new_domains"],
"errors": results["errors"] if "errors" in results and results["errors"] else None,
"timestamp": datetime.now().isoformat(),
}
except Exception as e:
logger.error("Error fetching IMAP reports: %s", str(e))
raise HTTPException(
status_code=500, detail="Failed to fetch reports. Check server logs for details."
) from e
@router.get("/status")
async def get_imap_status(_auth: dict = Depends(require_admin_auth)) -> Dict[str, Any]:
"""
Get the current status of IMAP polling background processes
Security: Requires authentication (X-API-Key or Bearer token)
"""
# In a real implementation this would check a persistent store
# or a global variable tracking the status of background tasks
# For now, returning simplified status
return {
"is_running": True, # In a real app, check if the background task is running
"last_check": None, # In production, track actual last check time
"next_check": None, # In production, calculate based on polling interval
"messages_processed": 0, # In production, track actual messages processed
"reports_found": 0, # In production, track reports found
"timestamp": datetime.now().isoformat(),
}