Files
FunguyBot/plugins/whois.py
T

131 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
WHOIS lookup plugin outputs a formatted code block with emojis and aligned columns.
"""
import logging
import whois
import ipaddress
import re
import asyncio
import simplematrixbotlib as botlib
from plugins.common import collapsible_summary, html_escape, code_block
def is_valid_domain(domain):
pattern = r'^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$|^[a-zA-Z0-9-]{1,63}$'
return re.match(pattern, domain) is not None
def is_valid_ip(ip):
try:
ipaddress.ip_address(ip)
return True
except ValueError:
return False
def _build_rows(data):
"""Build a list of (emoji, label, value) tuples from WHOIS data."""
rows = []
# Domain
domain_name = data.domain_name
if isinstance(domain_name, list):
domain_name = ', '.join(domain_name)
rows.append(('🌐', 'Domain', domain_name or 'N/A'))
# Registrar / WHOIS Server
if data.registrar:
rows.append(('🏢', 'Registrar', data.registrar))
if data.whois_server:
rows.append(('📡', 'WHOIS Server', data.whois_server))
# Dates
creation_date = data.creation_date
if creation_date:
if isinstance(creation_date, list):
creation_date = creation_date[0]
rows.append(('📅', 'Created', str(creation_date)))
updated_date = data.updated_date
if updated_date:
if isinstance(updated_date, list):
updated_date = updated_date[0]
rows.append(('📝', 'Updated', str(updated_date)))
expiration_date = data.expiration_date
if expiration_date:
if isinstance(expiration_date, list):
expiration_date = expiration_date[0]
rows.append(('', 'Expires', str(expiration_date)))
# Name servers
if data.name_servers:
ns_sorted = sorted(data.name_servers)
ns_text = ', '.join(ns_sorted[:5])
if len(ns_sorted) > 5:
ns_text += f' (+{len(ns_sorted)-5} more)'
rows.append(('🌍', 'Name Servers', ns_text))
# Status
if data.status:
status = data.status
if isinstance(status, list):
status = ', '.join(status[:3])
rows.append(('🔒', 'Status', str(status)))
# Contact info
if data.org:
rows.append(('🏛️', 'Organization', data.org))
if data.country:
rows.append(('🌍', 'Country', data.country))
if data.state:
rows.append(('🏙️', 'State', data.state))
if data.city:
rows.append(('🏡', 'City', data.city))
return rows
async def handle_command(room, message, bot, prefix, config):
match = botlib.MessageMatch(room, message, bot, prefix)
if match.is_not_from_this_bot() and match.prefix() and match.command("whois"):
args = match.args()
if len(args) < 1:
await bot.api.send_text_message(room.room_id, "Usage: !whois <domain/ip>\nExample: !whois example.com")
return
query = args[0].strip()
if not is_valid_domain(query) and not is_valid_ip(query):
await bot.api.send_text_message(room.room_id, f"Invalid input: {html_escape(query)}")
return
await bot.api.send_text_message(room.room_id, f"🔍 Performing WHOIS lookup for {html_escape(query)}...")
try:
loop = asyncio.get_running_loop()
data = await loop.run_in_executor(None, whois.whois, query)
rows = _build_rows(data)
sections = [{"title": "", "rows": rows}] # no section header
block = code_block(f"🌐 WHOIS Report: {html_escape(query)}", sections)
output = collapsible_summary(f"🌐 WHOIS Report: {html_escape(query)}", block)
await bot.api.send_markdown_message(room.room_id, output)
except whois.parser.PywhoisError as e:
await bot.api.send_text_message(room.room_id, f"❌ WHOIS lookup failed: {html_escape(str(e))}")
except Exception as e:
await bot.api.send_text_message(room.room_id, f"❌ Unexpected error: {html_escape(str(e))}")
# ---------------------------------------------------------------------------
# Plugin Metadata
# ---------------------------------------------------------------------------
__version__ = "1.2.1"
__author__ = "Funguy Bot"
__description__ = "Domain WHOIS lookup"
__help__ = """
<details>
<summary><strong>!whois</strong> WHOIS lookup</summary>
<pre>
!whois &lt;domain or IP&gt; Shows registrar, dates, nameservers, etc. in a clean table.
</pre>
</details>
"""