Working copy

This commit is contained in:
Hash Borgir 2024-02-12 14:41:01 -07:00
parent 4e635b0042
commit 992fcec9ae
15 changed files with 226 additions and 121 deletions

39
bot.py
View File

@ -1,9 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
# bot.py
import os import os
import logging import logging
from dotenv import load_dotenv import importlib
import simplematrixbotlib as botlib import simplematrixbotlib as botlib
from dotenv import load_dotenv
import time
# Load environment variables from .env file # Load environment variables from .env file
load_dotenv() load_dotenv()
@ -25,35 +28,37 @@ logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=lo
# Load plugins # Load plugins
PLUGINS_DIR = "plugins" PLUGINS_DIR = "plugins"
PLUGINS = {}
def load_plugins(): def load_plugins():
plugins = []
for plugin_file in os.listdir(PLUGINS_DIR): for plugin_file in os.listdir(PLUGINS_DIR):
if plugin_file.endswith(".py"): if plugin_file.endswith(".py"):
plugin_name = os.path.splitext(plugin_file)[0] plugin_name = os.path.splitext(plugin_file)[0]
try: try:
plugin_module = __import__(f"{PLUGINS_DIR}.{plugin_name}", fromlist=[""]) module = importlib.import_module(f"{PLUGINS_DIR}.{plugin_name}")
plugins.append(plugin_module) PLUGINS[plugin_name] = module
logging.info(f"Loaded plugin: {plugin_name}") logging.info(f"Loaded plugin: {plugin_name}")
except Exception as e: except Exception as e:
logging.error(f"Error loading plugin {plugin_name}: {e}") logging.error(f"Error loading plugin {plugin_name}: {e}")
return plugins
plugins = load_plugins() def reload_plugins():
global PLUGINS
PLUGINS = {}
load_plugins()
load_plugins()
@bot.listener.on_message_event @bot.listener.on_message_event
async def handle_commands(room, message): async def handle_commands(room, message):
""" match = botlib.MessageMatch(room, message, bot, PREFIX)
Function to handle incoming command messages. if match.is_not_from_this_bot() and match.prefix() and match.command("reload"):
if str(message.sender) == ADMIN_USER:
reload_plugins()
await bot.api.send_text_message(room.room_id, "Plugins reloaded successfully")
else:
await bot.api.send_text_message(room.room_id, "You are not authorized to reload plugins.")
Args: for plugin_name, plugin_module in PLUGINS.items():
room (Room): The Matrix room where the command was invoked. await plugin_module.handle_command(room, message, bot, PREFIX)
message (RoomMessage): The message object containing the command.
Returns:
None
"""
for plugin in plugins:
await plugin.handle_command(room, message, bot, PREFIX)
bot.run() bot.run()

View File

@ -18,28 +18,53 @@ async def handle_command(room, message, bot, PREFIX):
if match.is_not_from_this_bot() and match.prefix() and match.command("commands"): if match.is_not_from_this_bot() and match.prefix() and match.command("commands"):
logging.info("Fetching commands documentation") logging.info("Fetching commands documentation")
commands_message = """ commands_message = """
**Available Commands:** # 🍄 Funguy Bot Commands 🍄
**!fortune** 🃏 **!fortune**
Returns a random fortune message. Returns a random fortune message.
Executes the `/usr/games/fortune` utility and sends the output as a message to the chat room.
**!date** **!date**
Displays the current date and time. Displays the current date and time.
Fetches the current date and time using Python's `datetime` module and sends it in a formatted message to the chat room.
**!proxy** 💻 **!proxy**
Retrieves and tests random SOCKS5 and HTTP proxies. Retrieves a tested/working random SOCKS5 proxy.
Fetches a list of SOCKS5 proxies, tests their availability, and sends the first working proxy to the chat room.
**!isup <domain/ip>** 📶 **!isup <domain/ip>**
Checks if the specified domain or IP address is reachable. Checks if the specified domain or IP address is reachable.
Checks if the specified domain or IP address is reachable by attempting to ping it. If DNS resolution is successful, it checks HTTP and HTTPS service availability by sending requests to the domain.
**!karma <user>** **!karma <user>**
Retrieves the karma points for the specified user. Retrieves the karma points for the specified user.
Retrieves the karma points for the specified user from a database and sends them as a message to the chat room.
**!karma <user> up** **!karma <user> up**
Increases the karma points for the specified user by 1. Increases the karma points for the specified user by 1.
Increases the karma points for the specified user by 1 in the database and sends the updated points as a message to the chat room.
**!karma <user> down**
Decreases the karma points for the specified user by 1.
Decreases the karma points for the specified user by 1 in the database and sends the updated points as a message to the chat room.
# 🌟 Funguy Bot Credits 🌟
🧙 Creator & Developer: Hash Borgir (HB)
🎓 Academic Achievements:
- Bachelor of Computer Science (2004)
- Bachelor of Science, Cybersecurity & Information Assurance (2023)
- Master of Science, Cybersecurity & Information Assurance (ongoing)
🔐 Certifications:
- A+, Net+, Sec+, CySA+, Pentest+, Project+, ECES, ITILv4, SSCP, CCSP, MCP, MCSE
💼 Professional Profile:
- Website: [Hash Security](https://www.hashsecurity.net)
Hash Borgir, with a rich background in computer science and cybersecurity, is the author of 🍄Funguy Bot🍄.
**!karma <user> down**
Decreases the karma points for the specified user by 1.
""" """
await bot.api.send_markdown_message(room.room_id, commands_message) await bot.api.send_markdown_message(room.room_id, commands_message)
logging.info("Sent commands documentation to the room") logging.info("Sent commands documentation to the room")

View File

@ -23,6 +23,6 @@ async def handle_command(room, message, bot, PREFIX):
month = current_datetime.strftime("%B") month = current_datetime.strftime("%B")
year = current_datetime.strftime("%Y") year = current_datetime.strftime("%Y")
time = current_datetime.strftime("%I:%M:%S %p") time = current_datetime.strftime("%I:%M:%S %p")
date_message = f"Today is **{day_of_week}** of **{month}** in **{year}**. The time is **{time}**" date_message = f"📅 Today is **{day_of_week}** of **{month}** in **{year}**. The time is **{time}**"
await bot.api.send_markdown_message(room.room_id, date_message) await bot.api.send_markdown_message(room.room_id, date_message)
logging.info("Sent current date and time to the room") logging.info("Sent current date and time to the room")

View File

@ -18,6 +18,6 @@ async def handle_command(room, message, bot, PREFIX):
match = botlib.MessageMatch(room, message, bot, PREFIX) match = botlib.MessageMatch(room, message, bot, PREFIX)
if match.is_not_from_this_bot() and match.prefix() and match.command("fortune"): if match.is_not_from_this_bot() and match.prefix() and match.command("fortune"):
logging.info("Received !fortune command") logging.info("Received !fortune command")
fortune_output = subprocess.run(['/usr/games/fortune'], capture_output=True).stdout.decode('UTF-8') fortune_output = "🃏 " + subprocess.run(['/usr/games/fortune'], capture_output=True).stdout.decode('UTF-8')
await bot.api.send_text_message(room.room_id, fortune_output) await bot.api.send_markdown_message(room.room_id, fortune_output)
logging.info("Sent fortune to the room") logging.info("Sent fortune to the room")

View File

@ -1,9 +1,44 @@
# plugins/isup.py # plugins/isup.py
import os
import logging import logging
import aiohttp
import socket
import simplematrixbotlib as botlib import simplematrixbotlib as botlib
async def check_http(domain):
"""
Check if HTTP service is up for the given domain.
Args:
domain (str): The target domain.
Returns:
bool: True if HTTP service is up, False otherwise.
"""
try:
async with aiohttp.ClientSession() as session:
async with session.get(f"http://{domain}") as response:
return response.status == 200
except aiohttp.ClientError:
return False
async def check_https(domain):
"""
Check if HTTPS service is up for the given domain.
Args:
domain (str): The target domain.
Returns:
bool: True if HTTPS service is up, False otherwise.
"""
try:
async with aiohttp.ClientSession() as session:
async with session.get(f"https://{domain}") as response:
return response.status == 200
except aiohttp.ClientError:
return False
async def handle_command(room, message, bot, PREFIX): async def handle_command(room, message, bot, PREFIX):
""" """
Function to handle the !isup command. Function to handle the !isup command.
@ -20,18 +55,29 @@ async def handle_command(room, message, bot, PREFIX):
logging.info("Received !isup command") logging.info("Received !isup command")
args = match.args() args = match.args()
if len(args) != 1: if len(args) != 1:
await bot.api.send_text_message(room.room_id, "Usage: !isup <ipv4/ipv6/domain>") await bot.api.send_markdown_message(room.room_id, "Usage: !isup <ipv4/ipv6/domain>")
logging.info("Sent usage message to the room") logging.info("Sent usage message to the room")
return return
target = args[0] target = args[0]
# DNS resolution
try: try:
response = os.system(f"ping -c 1 {target}") ip_address = socket.gethostbyname(target)
if response == 0: logging.info(f"DNS resolution successful for {target}: {ip_address}")
await bot.api.send_text_message(room.room_id, f"{target} is up") await bot.api.send_markdown_message(room.room_id, f"✅ DNS resolution successful for **{target}**: **{ip_address}** (A record)")
except socket.gaierror:
logging.info(f"DNS resolution failed for {target}")
await bot.api.send_markdown_message(room.room_id, f"❌ DNS resolution failed for **{target}**")
return
# Check HTTP/HTTPS services
if await check_http(target):
await bot.api.send_markdown_message(room.room_id, f"🖧 **{target}** HTTP service is up")
logging.info(f"{target} HTTP service is up")
elif await check_https(target):
await bot.api.send_markdown_message(room.room_id, f"🖧 **{target}** HTTPS service is up")
logging.info(f"{target} HTTPS service is up")
else: else:
await bot.api.send_text_message(room.room_id, f"{target} is down") await bot.api.send_markdown_message(room.room_id, f"😕 **{target}** HTTP/HTTPS services are down")
logging.info(f"Sent status of {target} to the room") logging.info(f"{target} HTTP/HTTPS services are down")
except Exception as e:
await bot.api.send_text_message(room.room_id, f"Error: {e}")
logging.error(f"Error occurred while checking {target}: {e}")

View File

@ -29,15 +29,20 @@ async def handle_command(room, message, bot, PREFIX):
(username TEXT PRIMARY KEY, points INTEGER)''') (username TEXT PRIMARY KEY, points INTEGER)''')
c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (sender, 0)) c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (sender, 0))
c.execute('''SELECT points FROM karma WHERE username = ?''', (sender,)) c.execute('''SELECT points FROM karma WHERE username = ?''', (sender,))
points = c.fetchone()[0] row = c.fetchone()
conn.close() if row is not None:
await bot.api.send_text_message(room.room_id, f"{sender}'s karma points: {points}") points = row[0]
await bot.api.send_markdown_message(room.room_id, f"💗 {sender}'s karma points: {points}")
logging.info(f"Sent {sender}'s karma points ({points}) to the room") logging.info(f"Sent {sender}'s karma points ({points}) to the room")
else:
await bot.api.send_markdown_message(room.room_id, f"💗 {sender} does not have any karma points yet.")
logging.info(f"Sent message that {sender} does not have any karma points yet.")
conn.close()
elif len(args) == 1: elif len(args) == 1:
username = args[0] username = args[0]
if username == sender: if username == sender:
await bot.api.send_text_message(room.room_id, "You cannot modify your own karma.") await bot.api.send_markdown_message(room.room_id, "You cannot modify your own karma.")
logging.info("Sent self-modification warning message to the room") logging.info("Sent self-modification warning message to the room")
return return
@ -47,19 +52,24 @@ async def handle_command(room, message, bot, PREFIX):
(username TEXT PRIMARY KEY, points INTEGER)''') (username TEXT PRIMARY KEY, points INTEGER)''')
c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0)) c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0))
c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) c.execute('''SELECT points FROM karma WHERE username = ?''', (username,))
points = c.fetchone()[0] row = c.fetchone()
conn.close() if row is not None:
await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}") points = row[0]
await bot.api.send_markdown_message(room.room_id, f"💗 {username}'s karma points: {points}")
logging.info(f"Sent {username}'s karma points ({points}) to the room") logging.info(f"Sent {username}'s karma points ({points}) to the room")
else:
await bot.api.send_markdown_message(room.room_id, f"💗 {username} does not have any karma points yet.")
logging.info(f"Sent message that {username} does not have any karma points yet.")
conn.close()
elif len(args) == 2: elif len(args) == 2:
username, action = args username, action = args
if action not in ['up', 'down']: if action not in ['up', 'down']:
await bot.api.send_text_message(room.room_id, "Invalid action. Use 'up' or 'down'.") await bot.api.send_markdown_message(room.room_id, "Invalid action. Use 'up' or 'down'.")
logging.info("Sent invalid action message to the room") logging.info("Sent invalid action message to the room")
return return
if username == sender: if username == sender:
await bot.api.send_text_message(room.room_id, "You cannot modify your own karma.") await bot.api.send_markdown_message(room.room_id, "You cannot modify your own karma.")
logging.info("Sent self-modification warning message to the room") logging.info("Sent self-modification warning message to the room")
return return
@ -69,17 +79,23 @@ async def handle_command(room, message, bot, PREFIX):
(username TEXT PRIMARY KEY, points INTEGER)''') (username TEXT PRIMARY KEY, points INTEGER)''')
if action == 'up': if action == 'up':
c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0))
c.execute('''UPDATE karma SET points = points + 1 WHERE username = ?''', (username,)) c.execute('''UPDATE karma SET points = points + 1 WHERE username = ?''', (username,))
else: else:
c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0))
c.execute('''UPDATE karma SET points = points - 1 WHERE username = ?''', (username,)) c.execute('''UPDATE karma SET points = points - 1 WHERE username = ?''', (username,))
conn.commit() conn.commit()
c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) c.execute('''SELECT points FROM karma WHERE username = ?''', (username,))
points = c.fetchone()[0] row = c.fetchone()
conn.close() if row is not None:
points = row[0]
await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}") await bot.api.send_markdown_message(room.room_id, f"💗 {username}'s karma points: {points}")
logging.info(f"Sent {username}'s karma points ({points}) to the room") logging.info(f"Sent {username}'s karma points ({points}) to the room")
else: else:
await bot.api.send_text_message(room.room_id, "Usage: !karma [username] [up/down]") await bot.api.send_markdown_message(room.room_id, f"💗 {username} does not have any karma points yet.")
logging.info(f"Sent message that {username} does not have any karma points yet.")
conn.close()
else:
await bot.api.send_markdown_message(room.room_id, "☯ Usage: !karma [username] [up/down]")
logging.info("Sent usage message to the room") logging.info("Sent usage message to the room")

View File

@ -5,53 +5,69 @@ import logging
import random import random
import requests import requests
import socket import socket
import asyncio import ssl
import time import time
from datetime import datetime, timedelta
import simplematrixbotlib as botlib import simplematrixbotlib as botlib
# Function to test SOCKS4 proxies # Constants
async def test_socks4_proxy(proxy): SOCKS5_LIST_URL = 'https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt'
try: MAX_TRIES = 5
start_time = time.time() PROXY_LIST_FILENAME = 'socks5.txt'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) PROXY_LIST_EXPIRATION = timedelta(hours=8)
s.settimeout(5)
s.connect((proxy.split(':')[0], int(proxy.split(':')[1])))
latency = round((time.time() - start_time) * 1000, 2)
logging.info(f"Tested SOCKS4 proxy {proxy}. Latency: {latency} ms")
return True, latency
except Exception as e:
logging.error(f"Error testing SOCKS4 proxy {proxy}: {e}")
return False, None
# Function to test SOCKS5 proxies
async def test_socks5_proxy(proxy): async def test_socks5_proxy(proxy):
"""
Test a SOCKS5 proxy by attempting a connection and sending a request through it.
Args:
proxy (str): The SOCKS5 proxy address in the format 'ip:port'.
Returns:
bool: True if the proxy is working, False otherwise.
float: The latency in milliseconds if the proxy is working, None otherwise.
"""
try: try:
ip, port = proxy.split(':')
start_time = time.time() start_time = time.time()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) with socket.create_connection((ip, int(port)), timeout=5) as client:
s.settimeout(5) client.sendall(b'\x05\x01\x00')
s.connect((proxy.split(':')[0], int(proxy.split(':')[1]))) response = client.recv(2)
latency = round((time.time() - start_time) * 1000, 2) if response == b'\x05\x00':
logging.info(f"Tested SOCKS5 proxy {proxy}. Latency: {latency} ms") latency = int(round((time.time() - start_time) * 1000, 0))
logging.info(f"Successful connection to SOCKS5 proxy {proxy}. Latency: {latency} ms")
return True, latency return True, latency
else:
logging.info(f"Failed to connect to SOCKS5 proxy {proxy}: Connection refused")
return False, None
except Exception as e: except Exception as e:
logging.error(f"Error testing SOCKS5 proxy {proxy}: {e}") logging.error(f"Error testing SOCKS5 proxy {proxy}: {e}")
return False, None return False, None
# Function to test HTTP proxies async def download_proxy_list():
async def test_http_proxy(proxy): """
local_ip = requests.get("https://api.ipify.org").text Download the SOCKS5 proxy list file if it doesn't already exist or if it's expired.
Returns:
bool: True if the proxy list is downloaded or up-to-date, False otherwise.
"""
try: try:
response = requests.get("https://api.ipify.org", proxies={"http": proxy}, timeout=5).text if not os.path.exists(PROXY_LIST_FILENAME) or \
if response.strip() != local_ip.strip(): datetime.now() - datetime.fromtimestamp(os.path.getctime(PROXY_LIST_FILENAME)) > PROXY_LIST_EXPIRATION:
logging.info(f"Tested anonymous HTTP proxy {proxy}") logging.info("Downloading SOCKS5 proxy list")
response = requests.get(SOCKS5_LIST_URL, timeout=5)
with open(PROXY_LIST_FILENAME, 'w') as f:
f.write(response.text)
logging.info("Proxy list downloaded successfully")
return True return True
else: else:
logging.info(f"HTTP proxy {proxy} is not anonymous") logging.info("Proxy list already exists and is up-to-date")
return False return True
except Exception as e: except Exception as e:
logging.error(f"Error testing HTTP proxy {proxy}: {e}") logging.error(f"Error downloading proxy list: {e}")
return False return False
async def handle_command(room, message, bot, PREFIX): async def handle_command(room, message, bot, PREFIX):
""" """
Function to handle the !proxy command. Function to handle the !proxy command.
@ -66,38 +82,35 @@ async def handle_command(room, message, bot, PREFIX):
match = botlib.MessageMatch(room, message, bot, PREFIX) match = botlib.MessageMatch(room, message, bot, PREFIX)
if match.is_not_from_this_bot() and match.prefix() and match.command("proxy"): if match.is_not_from_this_bot() and match.prefix() and match.command("proxy"):
logging.info("Received !proxy command") logging.info("Received !proxy command")
# Download proxy list if needed
if not await download_proxy_list():
await bot.api.send_markdown_message(room.room_id, "Error downloading proxy list")
logging.error("Error downloading proxy list")
return
try: try:
# Fetch SOCKS4 proxy # Read proxies from file
socks4_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks4.txt', timeout=5).text.splitlines() with open(PROXY_LIST_FILENAME, 'r') as f:
random.shuffle(socks4_proxies) socks5_proxies = f.read().splitlines()
for proxy in socks4_proxies:
is_working, latency = await test_socks4_proxy(proxy)
if is_working:
await bot.api.send_text_message(room.room_id, f"SOCKS4 Proxy: {proxy} - Latency: {latency} ms")
break
# Fetch SOCKS5 proxy
socks5_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt', timeout=5).text.splitlines()
random.shuffle(socks5_proxies) random.shuffle(socks5_proxies)
for proxy in socks5_proxies:
is_working, latency = await test_socks5_proxy(proxy) # Test proxies
if is_working: socks5_proxy = None
await bot.api.send_text_message(room.room_id, f"SOCKS5 Proxy: {proxy} - Latency: {latency} ms") for proxy in socks5_proxies[:MAX_TRIES]:
success, latency = await test_socks5_proxy(proxy)
if success:
socks5_proxy = proxy
break break
# Fetch HTTP proxy # Send the first working anonymous proxy of each type to the Matrix room
http_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/http.txt', timeout=5).text.splitlines() if socks5_proxy:
random.shuffle(http_proxies) await bot.api.send_markdown_message(room.room_id, f"✅ Anonymous SOCKS5 Proxy: **{socks5_proxy}** - Latency: **{latency} ms**")
for proxy in http_proxies: logging.info(f"Sent SOCKS5 proxy {socks5_proxy} to the room")
is_working = await test_http_proxy(proxy) else:
if is_working: await bot.api.send_markdown_message(room.room_id, "❌ No working anonymous SOCKS5 proxy found")
await bot.api.send_text_message(room.room_id, f"HTTP Proxy: {proxy}") logging.info("No working anonymous SOCKS5 proxy found")
break
logging.info("Sent proxies to the room")
except asyncio.TimeoutError:
await bot.api.send_text_message(room.room_id, "Failed to fetch or test proxies. The operation timed out.")
logging.error("Proxy fetch and test operation timed out")
except Exception as e: except Exception as e:
await bot.api.send_text_message(room.room_id, f"An error occurred: {e}") logging.error(f"Error handling !proxy command: {e}")
logging.error(f"Error fetching or testing proxies: {e}") await bot.api.send_markdown_message(room.room_id, "❌ Error handling !proxy command")

View File

@ -31,9 +31,9 @@ async def handle_command(room, message, bot, PREFIX):
length = video.length length = video.length
views = video.views views = video.views
author = video.author author = video.author
info_message = f"""Title: {title} | Length: {length} seconds | Views: {views} | Description: {description}""" info_message = f"""**🎬🎝 Title:** {title} | **Length**: {length} sec | **Views:** {views} | **Description:** {description}"""
await bot.api.send_markdown_message(room.room_id, info_message) await bot.api.send_markdown_message(room.room_id, info_message)
logging.info("Sent YouTube video information to the room") logging.info("Sent YouTube video information to the room")
except Exception as e: except Exception as e:
logging.error(f"Error fetching YouTube video information: {str(e)}") logging.error(f"Error fetching YouTube video information: {str(e)}")
await bot.api.send_text_message(room.room_id, "Error fetching YouTube video information.") # await bot.api.send__message(room.room_id, "Error fetching YouTube video information.")