"""
This plugin provides DNSDumpster.com integration for domain reconnaissance and DNS mapping.
"""
import logging
import os
import requests
import simplematrixbotlib as botlib
from dotenv import load_dotenv
# Load environment variables from .env file
plugin_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(plugin_dir)
dotenv_path = os.path.join(parent_dir, '.env')
load_dotenv(dotenv_path)
DNSDUMPSTER_API_KEY = os.getenv("DNSDUMPSTER_KEY", "")
DNSDUMPSTER_API_BASE = "https://api.dnsdumpster.com"
async def handle_command(room, message, bot, prefix, config):
    """
    Function to handle DNSDumpster commands.
    Args:
        room (Room): The Matrix room where the command was invoked.
        message (RoomMessage): The message object containing the command.
        bot (Bot): The bot object.
        prefix (str): The command prefix.
        config (dict): Configuration parameters.
    Returns:
        None
    """
    match = botlib.MessageMatch(room, message, bot, prefix)
    if match.is_not_from_this_bot() and match.prefix() and match.command("dnsdumpster"):
        logging.info("Received !dnsdumpster command")
        # Check if API key is configured
        if not DNSDUMPSTER_API_KEY:
            await bot.api.send_text_message(
                room.room_id,
                "DNSDumpster API key not configured. Please set DNSDUMPSTER_KEY environment variable."
            )
            logging.error("DNSDumpster API key not configured")
            return
        args = match.args()
        if len(args) < 1:
            await show_usage(room, bot)
            return
        # Check if it's a test command or domain lookup
        if args[0].lower() == "test":
            await test_dnsdumpster_connection(room, bot)
        else:
            # Treat the first argument as the domain
            domain = args[0].lower().strip()
            await dnsdumpster_domain_lookup(room, bot, domain)
async def show_usage(room, bot):
    """Display DNSDumpster command usage."""
    usage = """
🔍 DNSDumpster Commands:
!dnsdumpster <domain_name> - Get comprehensive DNS reconnaissance for a domain
!dnsdumpster test - Test API connection
Examples:
• !dnsdumpster google.com
• !dnsdumpster github.com
• !dnsdumpster example.com
Rate Limit: 1 request per 2 seconds
"""
    await bot.api.send_markdown_message(room.room_id, usage)
async def test_dnsdumpster_connection(room, bot):
    """Test DNSDumpster API connection."""
    try:
        test_domain = "google.com"  # Changed from example.com to google.com
        url = f"{DNSDUMPSTER_API_BASE}/domain/{test_domain}"
        headers = {
            "X-API-Key": DNSDUMPSTER_API_KEY
        }
        logging.info(f"Testing DNSDumpster API with domain: {test_domain}")
        response = requests.get(url, headers=headers, timeout=15)
        debug_info = f"🔧 DNSDumpster API Test
"
        debug_info += f"Status Code: {response.status_code}
"
        debug_info += f"Test Domain: {test_domain}
"
        debug_info += f"Headers Used: X-API-Key
"
        if response.status_code == 200:
            data = response.json()
            debug_info += "✅ SUCCESS - API is working!
"
            debug_info += f"Response Keys: {list(data.keys())}
"
            # Show some sample data
            if data.get('a'):
                debug_info += f"A Records Found: {len(data['a'])}
"
            if data.get('ns'):
                debug_info += f"NS Records Found: {len(data['ns'])}
"
            if data.get('total_a_recs'):
                debug_info += f"Total A Records: {data['total_a_recs']}
"
        elif response.status_code == 400:
            debug_info += "❌ Bad Request - Check domain format
"
            debug_info += f"Response: {response.text[:200]}
"
        elif response.status_code == 401:
            debug_info += "❌ Unauthorized - Invalid API key
"
        elif response.status_code == 429:
            debug_info += "⚠️ Rate Limit Exceeded - Wait 2 seconds
"
        else:
            debug_info += f"❌ Error: {response.status_code} - {response.text[:200]}
"
        await bot.api.send_markdown_message(room.room_id, debug_info)
    except Exception as e:
        await bot.api.send_text_message(room.room_id, f"Test failed: {str(e)}")
async def dnsdumpster_domain_lookup(room, bot, domain):
    """Get comprehensive DNS reconnaissance for a domain."""
    try:
        url = f"{DNSDUMPSTER_API_BASE}/domain/{domain}"
        headers = {
            "X-API-Key": DNSDUMPSTER_API_KEY
        }
        logging.info(f"Fetching DNSDumpster data for domain: {domain}")
        # Send initial processing message
        await bot.api.send_text_message(room.room_id, f"🔍 Processing DNS reconnaissance for {domain}...")
        response = requests.get(url, headers=headers, timeout=30)
        if response.status_code == 400:
            await bot.api.send_text_message(room.room_id, f"Bad request - check domain format: {domain}")
            return
        elif response.status_code == 401:
            await bot.api.send_text_message(room.room_id, "Invalid DNSDumpster API key")
            return
        elif response.status_code == 403:
            await bot.api.send_text_message(room.room_id, "Access denied - check API key permissions")
            return
        elif response.status_code == 429:
            await bot.api.send_text_message(room.room_id, "Rate limit exceeded - wait 2 seconds between requests")
            return
        elif response.status_code != 200:
            await bot.api.send_text_message(room.room_id, f"DNSDumpster API error: {response.status_code} - {response.text[:100]}")
            return
        data = response.json()
        logging.info(f"DNSDumpster response keys: {list(data.keys())}")
        # Format the comprehensive DNS report
        output = await format_dnsdumpster_report(domain, data)
        await bot.api.send_markdown_message(room.room_id, output)
        logging.info(f"Sent DNSDumpster data for {domain}")
    except requests.exceptions.Timeout:
        await bot.api.send_text_message(room.room_id, "DNSDumpster API request timed out")
        logging.error("DNSDumpster API timeout")
    except Exception as e:
        await bot.api.send_text_message(room.room_id, f"Error fetching DNSDumpster data: {str(e)}")
        logging.error(f"Error in dnsdumpster_domain_lookup: {e}")
async def format_dnsdumpster_report(domain, data):
    """Format DNSDumpster JSON response into a readable report."""
    output = f"🔍 DNSDumpster Report: {domain}
"
    # Summary statistics
    if data.get('total_a_recs'):
        output += f"📊 Summary
"
        output += f"  • Total A Records: {data['total_a_recs']}
"
    # A Records - Show ALL records
    if data.get('a') and data['a']:
        output += f"
📍 A Records (IPv4) - {len(data['a'])} found
"
        for record in data['a']:  # Show ALL A records
            host = record.get('host', 'N/A')
            ips = record.get('ips', [])
            output += f"  • {host}
"
            for ip_info in ips:  # Show ALL IPs per host
                ip = ip_info.get('ip', 'N/A')
                country = ip_info.get('country', 'Unknown')
                asn_name = ip_info.get('asn_name', 'Unknown')
                output += f"    └─ {ip} ({country})
"
                output += f"       └─ {asn_name}
"
                # Show banner information if available
                banners = ip_info.get('banners', {})
                if banners.get('http') or banners.get('https'):
                    output += f"       └─ Web Services: "
                    services = []
                    if banners.get('http'):
                        services.append("HTTP")
                    if banners.get('https'):
                        services.append("HTTPS")
                    output += f"{', '.join(services)}
"
    # NS Records - Show ALL records
    if data.get('ns') and data['ns']:
        output += f"
🔗 NS Records (Name Servers) - {len(data['ns'])} found
"
        for record in data['ns']:  # Show ALL NS records
            host = record.get('host', 'N/A')
            ips = record.get('ips', [])
            output += f"  • {host}
"
            for ip_info in ips:  # Show ALL IPs
                ip = ip_info.get('ip', 'N/A')
                country = ip_info.get('country', 'Unknown')
                output += f"    └─ {ip} ({country})
"
    # MX Records - Show ALL records
    if data.get('mx') and data['mx']:
        output += f"
📧 MX Records (Mail Servers) - {len(data['mx'])} found
"
        for record in data['mx']:  # Show ALL MX records
            host = record.get('host', 'N/A')
            ips = record.get('ips', [])
            output += f"  • {host}
"
            for ip_info in ips:  # Show ALL IPs
                ip = ip_info.get('ip', 'N/A')
                country = ip_info.get('country', 'Unknown')
                output += f"    └─ {ip} ({country})
"
    # CNAME Records - Show ALL records
    if data.get('cname') and data['cname']:
        output += f"
🔀 CNAME Records - {len(data['cname'])} found
"
        for record in data['cname']:  # Show ALL CNAME records
            host = record.get('host', 'N/A')
            target = record.get('target', 'N/A')
            output += f"  • {host} → {target}
"
    # TXT Records - Show ALL records
    if data.get('txt') and data['txt']:
        output += f"
📄 TXT Records - {len(data['txt'])} found
"
        for txt in data['txt']:  # Show ALL TXT records
            # Truncate very long TXT records but show more content
            if len(txt) > 200:
                txt = txt[:200] + "..."
            output += f"  • {txt}
"
    # Additional record types that might be present - Show ALL records
    other_records = ['aaaa', 'srv', 'soa', 'ptr']
    for record_type in other_records:
        if data.get(record_type) and data[record_type]:
            output += f"
🔧 {record_type.upper()} Records - {len(data[record_type])} found
"
            for record in data[record_type]:  # Show ALL records
                if isinstance(record, dict):
                    # Format dictionary records nicely
                    record_str = ", ".join([f"{k}: {v}" for k, v in record.items()])
                    if len(record_str) > 150:
                        record_str = record_str[:150] + "..."
                    output += f"  • {record_str}
"
                else:
                    output += f"  • {record}
"
    # Add rate limit reminder
    output += "
💡 Rate Limit: 1 request per 2 seconds"
    # Always wrap in collapsible details since we're showing all results
    output = f"🔍 DNSDumpster Report: {domain} (Click to expand)
{output} "
    return output