diff --git a/funguy.conf b/funguy.conf index 5ef4f36..81a6589 100644 --- a/funguy.conf +++ b/funguy.conf @@ -8,4 +8,5 @@ store_path = "./store/" allowlist = [] blocklist = [] admin_user = "@hashborgir:mozilla.org" -prefix = "!!" +prefix = "!" +config_file = "funguy.conf" diff --git a/funguy.py b/funguy.py index 5efcb25..65598dd 100755 --- a/funguy.py +++ b/funguy.py @@ -60,11 +60,9 @@ creds = botlib.Creds(MATRIX_URL, MATRIX_USER, MATRIX_PASS) config = FunguyConfig() bot = botlib.Bot(creds, config) -PREFIX = config.prefix - @bot.listener.on_message_event async def handle_commands(room, message): - match = botlib.MessageMatch(room, message, bot, PREFIX) + match = botlib.MessageMatch(room, message, bot, config.prefix) if match.is_not_from_this_bot() and match.prefix() and match.command("reload"): if str(message.sender) == config.admin_user: reload_plugins() @@ -73,7 +71,7 @@ async def handle_commands(room, message): await bot.api.send_text_message(room.room_id, "You are not authorized to reload plugins.") for plugin_name, plugin_module in PLUGINS.items(): - await plugin_module.handle_command(room, message, bot, PREFIX, config) + await plugin_module.handle_command(room, message, bot, config.prefix, config) if match.is_not_from_this_bot() and match.prefix() and match.command("rehash"): diff --git a/plugins/config.py b/plugins/config.py index 9de70b4..d71ce31 100644 --- a/plugins/config.py +++ b/plugins/config.py @@ -20,10 +20,11 @@ class FunguyConfig(botlib.Config): # Load configuration from file self.load_toml(config_file) - logging.info("Loaded configuration from funguy.conf") + logging.info(f"Loaded configuration from {config_file}") _admin_user: str = "" _prefix: str = "" + _config_file: str= "" # Define getters and setters for custom configuration options @property @@ -42,6 +43,15 @@ class FunguyConfig(botlib.Config): def prefix(self, value): self._prefix = value + @property + def config_file(self): + return self._config_file + + @config_file.setter + def config_file(self, value): + self._config_file = value + + # Method to load configuration from file def load_config(self, config_file): """ @@ -53,8 +63,9 @@ class FunguyConfig(botlib.Config): Returns: None """ - self.__init__() - logging.info("Loaded configuration from funguy.conf") + self.load_toml(config_file) + logging.info(f"Loaded configuration from {config_file}") + # Method to save configuration to file def save_config(self, config_file): @@ -68,9 +79,9 @@ class FunguyConfig(botlib.Config): None """ self.save_toml(config_file) - logging.info("Saved configuration to funguy.conf") + logging.info(f"Saved configuration to {config_file}") -async def handle_command(room, message, bot, PREFIX, config): +async def handle_command(room, message, bot, prefix, config): """ Function to handle commands related to bot configuration. @@ -84,7 +95,7 @@ async def handle_command(room, message, bot, PREFIX, config): Returns: None """ - 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("set"): args = match.args() if len(args) != 2: @@ -113,10 +124,13 @@ async def handle_command(room, message, bot, PREFIX, config): else: await bot.api.send_text_message(room.room_id, "Invalid configuration option") - elif match.is_not_from_this_bot() and match.prefix() and match.command("save"): - config.save_config("funguy.conf") - config.load_config("funguy.conf") - await bot.api.send_text_message(room.room_id, "Configuration saved & reloaded") + elif match.is_not_from_this_bot() and match.prefix() and match.command("saveconf"): + config.save_config(config.config_file) + await bot.api.send_text_message(room.room_id, "Configuration saved") + + elif match.is_not_from_this_bot() and match.prefix() and match.command("loadconf"): + config.load_config(config.config_file) + await bot.api.send_text_message(room.room_id, "Configuration loaded") elif match.is_not_from_this_bot() and match.prefix() and match.command("show"): admin_user = config.admin_user diff --git a/plugins/date.py b/plugins/date.py index 2cc65d9..4d73867 100644 --- a/plugins/date.py +++ b/plugins/date.py @@ -8,7 +8,7 @@ import datetime import logging import simplematrixbotlib as botlib -async def handle_command(room, message, bot, PREFIX, config): +async def handle_command(room, message, bot, prefix, config): """ Function to handle the !date command. @@ -19,7 +19,7 @@ async def handle_command(room, message, bot, PREFIX, config): Returns: None """ - 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("date"): logging.info("Fetching current date and time") current_datetime = datetime.datetime.now() diff --git a/plugins/disabled/ai-music.py b/plugins/disabled/ai-music.py deleted file mode 100644 index fe71674..0000000 --- a/plugins/disabled/ai-music.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -This plugin provides a command to interact with the music knowledge A.I. -""" -# plugins/ai-music.py - -import logging -import requests -import json -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !music command. - - 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. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("music"): - logging.info("Received !music command") - args = match.args() - if len(args) < 1: - await bot.api.send_text_message(room.room_id, "Usage: !music [prompt]") - logging.info("Sent usage message to the room") - return - - prompt = ' '.join(args) - - # Prepare data for the API request - url = "http://127.0.0.1:5000/v1/completions" - headers = { - "Content-Type": "application/json" - } - - data = { - "prompt": "[INST]You are FunguyFlows, an AI music expert bot with access to a vast repository of knowledge encompassing every facet of music, spanning genres, artists, bands, compositions, albums, lyrics, music theory, composition techniques, composers, music history, music appreciation, and more. Your role is to serve as an invaluable resource and guide within the realm of music, offering comprehensive insights, recommendations, and assistance to music enthusiasts, students, professionals, and curious minds alike.Drawing upon humanity's collective knowledge and expertise in music, your database contains a wealth of information sourced from authoritative texts, scholarly articles, historical archives, musical compositions, biographies, discographies, and cultural repositories. This rich repository enables you to provide accurate, detailed, and insightful responses to a wide range of inquiries, covering an extensive array of topics related to music theory, composition, performance, history, and appreciation.As an AI music expert, your knowledge extends across various genres, including classical, jazz, rock, pop, hip-hop, electronic, folk, world music, and beyond. You possess a deep understanding of musical concepts such as melody, harmony, rhythm, timbre, form, dynamics, and texture, allowing you to analyze and interpret musical compositions with precision and clarity.In addition to your expertise in music theory and composition, you are well-versed in the works of renowned composers throughout history, from the classical masters of Bach, Mozart, and Beethoven to contemporary innovators like John Williams, Philip Glass, and Hans Zimmer. You can provide detailed biographical information, analysis of their compositions, and insights into their lasting impact on the world of music.Your knowledge of music history is extensive, spanning centuries of cultural evolution and musical innovation. From the Gregorian chants of the medieval period to the avant-garde experiments of the 20th century, you can trace the development of musical styles, movements, and traditions across different regions and epochs, shedding light on the social, political, and artistic contexts that shaped musical expression throughout history.Furthermore, your expertise encompasses a diverse range of topics related to music appreciation, including techniques for active listening, critical analysis of musical performances, understanding musical genres and styles, exploring the cultural significance of music, and engaging with music as a form of creative expression, emotional communication, and cultural identity.Whether users seek recommendations for discovering new artists and albums, assistance with analyzing musical compositions, insights into music theory concepts, guidance on composing their own music, or historical context for understanding musical traditions, you are poised to provide informative, engaging, and enriching responses tailored to their interests and inquiries.As an AI music expert bot, your mission is to inspire curiosity, deepen understanding, and foster appreciation for the diverse and multifaceted world of music. By sharing your knowledge, passion, and enthusiasm for music, you aim to empower individuals to explore, create, and connect through the universal language of sound. Embrace your role as a trusted guide and mentor within the realm of music, and let your expertise illuminate the path for music lovers and learners alike, one harmonious interaction at a time. You will only answer questions about music, and nothing else. Now... tell me about: "+prompt+"[/INST]", - "max_tokens": 1024, - "temperature": 1.31, - "top_p": 0.14, - "top_k": 49, - "seed": -1, - "stream": False, - "repetition_penalty": 1.17 - } - - # Make HTTP request to the API endpoint - try: - response = requests.post(url, headers=headers, json=data, verify=False) - response.raise_for_status() # Raise HTTPError for bad responses - payload = response.json() - new_text = payload['choices'][0]['text'] - await bot.api.send_markdown_message(room.room_id, new_text) - logging.info("Sent generated text to the room") - except requests.exceptions.RequestException as e: - logging.error(f"HTTP request failed for '{prompt}': {e}") - await bot.api.send_text_message(room.room_id, f"Error generating text: {e}") diff --git a/plugins/disabled/ai-tech.py b/plugins/disabled/ai-tech.py deleted file mode 100644 index 4b614fd..0000000 --- a/plugins/disabled/ai-tech.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -This plugin provides a command to interact with the LLM for Tech/IT/Security/Selfhosting/Programming etc. -""" - -# plugins/ai-tech.py - -import logging -import requests -import json -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !funguy command. - - 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. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("funguy"): - logging.info("Received !funguy command") - args = match.args() - if len(args) < 1: - await bot.api.send_text_message(room.room_id, "Usage: !funguy [prompt]") - logging.info("Sent usage message to the room") - return - - prompt = ' '.join(args) - - # Prepare data for the API request - url = "http://127.0.0.1:5000/v1/completions" - headers = { - "Content-Type": "application/json" - } - - data = { - "prompt": "[INST]You are Funguy, a language model deployed as a chatbot for a community chat room hosted on Matrix. The chat room focuses on discussions related to self-hosting, system administration, cybersecurity, homelab setups, programming, coding, and general IT/tech topics. Your role is to assist users within the community by providing helpful responses and guidance on various technical matters. It's essential to keep your replies concise and relevant, addressing users' queries effectively while maintaining a friendly and approachable demeanor. Remember to prioritize clarity and brevity in your interactions to ensure a positive user experience within the chat room environment. You are ChatGPT, an AI language model designed to serve as a chatbot within a vibrant and diverse community chat room hosted on the Matrix platform. This chat room acts as a hub for enthusiasts and professionals alike, engaging in discussions spanning a wide array of technical topics, including self-hosting, system administration, cybersecurity, homelab setups, programming, coding, and general IT/tech inquiries. Your primary objective is to act as a reliable and knowledgeable assistant, offering assistance, guidance, and solutions to the community members as they navigate through their technical challenges and endeavors.Given the broad spectrum of topics discussed within the community, it's crucial for you to possess a comprehensive understanding of various domains within the realm of technology. As such, your knowledge should encompass not only the fundamentals of programming languages, software development methodologies, and system administration principles but also extend to cybersecurity best practices, networking protocols, cloud computing, database management, and beyond. Your role as a chatbot is multifaceted and dynamic. You'll be tasked with responding to a wide range of queries, ranging from beginner-level inquiries seeking clarification on basic concepts to advanced discussions requiring nuanced insights and problem-solving skills. Whether it's troubleshooting code errors, configuring network settings, securing server environments, optimizing database performance, or recommending suitable homelab hardware, your goal is to provide accurate, actionable, and helpful responses tailored to the needs of the community members. In addition to offering direct assistance, you should also strive to foster a collaborative and supportive atmosphere within the chat room. Encourage knowledge sharing, facilitate discussions, and celebrate the achievements of community members as they tackle technical challenges and embark on learning journeys. By promoting a culture of learning and collaboration, you'll contribute to the growth and cohesion of the community, empowering individuals to expand their skill sets and achieve their goals within the realm of technology. As you engage with users within the chat room, prioritize brevity and clarity in your responses. While it's essential to provide comprehensive and accurate information, it's equally important to convey it in a concise and easily understandable manner. Avoid overly technical jargon or convoluted explanations that may confuse or overwhelm community members, opting instead for straightforward explanations and practical solutions whenever possible. Remember, your ultimate objective is to be a trusted ally and resource for the members of the community as they navigate the ever-evolving landscape of technology. By leveraging your expertise, empathy, and problem-solving abilities, you'll play a vital role in facilitating knowledge exchange, fostering collaboration, and empowering individuals to succeed in their technical endeavors. As you embark on this journey as a chatbot within the Matrix community, embrace the opportunity to make a meaningful and positive impact, one helpful interaction at a time."+prompt+"[/INST]", - "max_tokens": 1024, - "temperature": 1.31, - "top_p": 0.14, - "top_k": 49, - "seed": -1, - "stream": False, - "repetition_penalty": 1.17 - } - - # Make HTTP request to the API endpoint - try: - response = requests.post(url, headers=headers, json=data, verify=False) - response.raise_for_status() # Raise HTTPError for bad responses - payload = response.json() - new_text = payload['choices'][0]['text'] - await bot.api.send_markdown_message(room.room_id, new_text) - logging.info("Sent generated text to the room") - except requests.exceptions.RequestException as e: - logging.error(f"HTTP request failed for '{prompt}': {e}") - await bot.api.send_text_message(room.room_id, f"Error generating text: {e}") diff --git a/plugins/disabled/commands.py b/plugins/disabled/commands.py deleted file mode 100644 index 8f1ba7d..0000000 --- a/plugins/disabled/commands.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -This plugin provides a command to display the list of available commands and their descriptions. -""" - -# plugins/commands.py - -import logging -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !commands command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("commands"): - logging.info("Fetching commands documentation") - commands_message = """ -# 🍄 Funguy Bot Commands 🍄 - -🃏 **!fortune** -Returns a random fortune message. -Executes the `/usr/games/fortune` utility and sends the output as a message to the chat room. - -⏰ **!date** -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** -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]** -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]** -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** -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 [prompt] -An AI large language model designed to serve as a chatbot within a vibrant and diverse community chat room hosted on the Matrix platform. -(Currently loaded model: **TheBloke_Mistral-7B-Instruct-v0.2-GPTQ** - -🎝 **!music [prompt]** -Your music expert! Try it out. - ---- - -# 🌟 Funguy Bot Credits 🌟 - -🧙‍♂️ Creator & Developer: - - Hash Borgir is the author of 🍄Funguy Bot🍄. (@hashborgir:mozilla.org) - -# Join our Matrix Room: - -[Self-hosting | Security | Sysadmin | Homelab | Programming](https://chat.mozilla.org/#/room/#selfhosting:mozilla.org) - """ - await bot.api.send_markdown_message(room.room_id, commands_message) - logging.info("Sent commands documentation to the room") diff --git a/plugins/disabled/config.py b/plugins/disabled/config.py deleted file mode 100644 index 5f68bef..0000000 --- a/plugins/disabled/config.py +++ /dev/null @@ -1,131 +0,0 @@ -# plugins/config.py - -import os -import logging -import simplematrixbotlib as botlib - -class FunguyConfig(botlib.Config): - """ - Custom configuration class for the Funguy bot. - Extends the base Config class to provide additional configuration options. - - Args: - config_file (str): Path to the configuration file. - """ - def __init__(self, config_file): - super().__init__() - - # Define custom configuration options here - self.admin_user = "" - self.prefix = "!" - - # Load configuration from file - self.load_toml(config_file) - logging.info("Loaded configuration from funguy.conf") - - # Define getters and setters for custom configuration options - @property - def admin_user(self): - return self._admin_user - - @admin_user.setter - def admin_user(self, value): - self._admin_user = value - - @property - def prefix(self): - return self._prefix - - @prefix.setter - def prefix(self, value): - self._prefix = value - - # Method to load configuration from file - def load_config(self, config_file): - """ - Load configuration options from a TOML file. - - Args: - config_file (str): Path to the configuration file. - - Returns: - None - """ - self.load_toml(config_file) - logging.info("Loaded configuration from funguy.conf") - - # Method to save configuration to file - def save_config(self, config_file): - """ - Save configuration options to a TOML file. - - Args: - config_file (str): Path to the configuration file. - - Returns: - None - """ - self.save_toml(config_file) - logging.info("Saved configuration to funguy.conf") - -async def handle_command(room, message, bot, PREFIX, config): - """ - Function to handle commands related to bot configuration. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - bot (Bot): The bot instance. - PREFIX (str): The bot command prefix. - config (FunguyConfig): The bot configuration instance. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("set"): - args = match.args() - if len(args) != 2: - await bot.api.send_text_message(room.room_id, "Usage: !set ") - return - option, value = args - if option == "admin_user": - config.admin_user = value - await bot.api.send_text_message(room.room_id, f"Admin user set to {value}") - elif option == "prefix": - config.prefix = value - await bot.api.send_text_message(room.room_id, f"Prefix set to {value}") - else: - await bot.api.send_text_message(room.room_id, "Invalid configuration option") - - elif match.is_not_from_this_bot() and match.prefix() and match.command("get"): - args = match.args() - if len(args) != 1: - await bot.api.send_text_message(room.room_id, "Usage: !get ") - return - option = args[0] - if option == "admin_user": - await bot.api.send_text_message(room.room_id, f"Admin user: {config.admin_user}") - elif option == "prefix": - await bot.api.send_text_message(room.room_id, f"Prefix: {config.prefix}") - else: - await bot.api.send_text_message(room.room_id, "Invalid configuration option") - - elif match.is_not_from_this_bot() and match.prefix() and match.command("save"): - config.save_config("funguy.conf") - await bot.api.send_text_message(room.room_id, "Configuration saved") - - elif match.is_not_from_this_bot() and match.prefix() and match.command("load"): - config.load_config("funguy.conf") - await bot.api.send_text_message(room.room_id, "Configuration loaded") - - elif match.is_not_from_this_bot() and match.prefix() and match.command("show"): - admin_user = config.admin_user - prefix = config.prefix - await bot.api.send_text_message(room.room_id, f"Admin user: {admin_user}, Prefix: {prefix}") - - elif match.is_not_from_this_bot() and match.prefix() and match.command("reset"): - config.admin_user = "" - config.prefix = "!" - await bot.api.send_text_message(room.room_id, "Configuration reset") - diff --git a/plugins/disabled/date.py b/plugins/disabled/date.py deleted file mode 100644 index 743f8b1..0000000 --- a/plugins/disabled/date.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -This plugin provides a command to get the current date -""" - -# plugins/date.py - -import datetime -import logging -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, config): - PREFIX = config.prefix - """ - Function to handle the !date command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("date"): - logging.info("Fetching current date and time") - current_datetime = datetime.datetime.now() - day_of_week = current_datetime.strftime("%A") - month = current_datetime.strftime("%B") - year = current_datetime.strftime("%Y") - time = current_datetime.strftime("%I:%M:%S %p") - 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) - logging.info("Sent current date and time to the room") diff --git a/plugins/disabled/fortune.py b/plugins/disabled/fortune.py deleted file mode 100644 index 474dd43..0000000 --- a/plugins/disabled/fortune.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -This plugin provides a command to get a random fortune message. -""" -# plugins/fortune.py - -import subprocess -import logging -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !fortune command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("fortune"): - logging.info("Received !fortune command") - fortune_output = "🃏 " + subprocess.run(['/usr/games/fortune'], capture_output=True).stdout.decode('UTF-8') - await bot.api.send_markdown_message(room.room_id, fortune_output) - logging.info("Sent fortune to the room") diff --git a/plugins/disabled/isup.py b/plugins/disabled/isup.py deleted file mode 100644 index b50ffe4..0000000 --- a/plugins/disabled/isup.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -This plugin provides a command to check if a website or server is up. -""" - -# plugins/isup.py - -import logging -import aiohttp -import socket -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): - """ - Function to handle the !isup command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("isup"): - logging.info("Received !isup command") - args = match.args() - if len(args) != 1: - await bot.api.send_markdown_message(room.room_id, "Usage: !isup ") - logging.info("Sent usage message to the room") - return - - target = args[0] - - # DNS resolution - try: - ip_address = socket.gethostbyname(target) - logging.info(f"DNS resolution successful for {target}: {ip_address}") - 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: - await bot.api.send_markdown_message(room.room_id, f"😕 **{target}** HTTP/HTTPS services are down") - logging.info(f"{target} HTTP/HTTPS services are down") diff --git a/plugins/disabled/karma.py b/plugins/disabled/karma.py deleted file mode 100644 index d74012d..0000000 --- a/plugins/disabled/karma.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -This plugin provides a command to manage karma points for users. -""" - - -# plugins/karma.py - -import sqlite3 -import logging -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !karma command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("karma"): - logging.info("Received !karma command") - args = match.args() - sender = str(message.sender) - - if len(args) == 0: - # Query sender's own karma - conn = sqlite3.connect('karma.db') - c = conn.cursor() - c.execute('''CREATE TABLE IF NOT EXISTS karma - (username TEXT PRIMARY KEY, points INTEGER)''') - c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (sender, 0)) - c.execute('''SELECT points FROM karma WHERE username = ?''', (sender,)) - row = c.fetchone() - if row is not None: - 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") - 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: - username = args[0] - - if username == sender: - 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") - return - - conn = sqlite3.connect('karma.db') - c = conn.cursor() - c.execute('''CREATE TABLE IF NOT EXISTS karma - (username TEXT PRIMARY KEY, points INTEGER)''') - c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0)) - c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) - row = c.fetchone() - if row is not None: - 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") - 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: - username, action = args - if action not in ['up', '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") - return - - if username == sender: - 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") - return - - conn = sqlite3.connect('karma.db') - c = conn.cursor() - c.execute('''CREATE TABLE IF NOT EXISTS karma - (username TEXT PRIMARY KEY, points INTEGER)''') - - 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,)) - else: - c.execute('''INSERT OR IGNORE INTO karma (username, points) VALUES (?, ?)''', (username, 0)) - c.execute('''UPDATE karma SET points = points - 1 WHERE username = ?''', (username,)) - - conn.commit() - c.execute('''SELECT points FROM karma WHERE username = ?''', (username,)) - row = c.fetchone() - if row is not None: - 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") - 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() - else: - await bot.api.send_markdown_message(room.room_id, "☯ Usage: !karma [username] [up/down]") - logging.info("Sent usage message to the room") diff --git a/plugins/disabled/load_plugin.py b/plugins/disabled/load_plugin.py deleted file mode 100644 index dd3ad95..0000000 --- a/plugins/disabled/load_plugin.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -This plugin provides a command to load individual plugins from local or remote sources -""" - -# plugins/load_plugin.py - -import os -import logging -import importlib -import simplematrixbotlib as botlib - -# Bot configuration settings -ADMIN_USER = "@hashborgir:mozilla.org" - -PLUGINS = {} - -async def load_plugin(plugin_name): - try: - module = importlib.import_module(f"{plugin_name}") - PLUGINS[plugin_name] = module - logging.info(f"Loaded plugin: {plugin_name}") - return True - except ModuleNotFoundError: - logging.error(f"Plugin module '{plugin_name}' not found") - except Exception as e: - logging.error(f"Error loading plugin '{plugin_name}': {e}") - return False - -async def handle_command(room, message, bot, PREFIX): - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("load"): - if str(message.sender) == ADMIN_USER: - args = match.args() - if len(args) != 1: - await bot.api.send_text_message(room.room_id, "Usage: !load ") - else: - plugin_name = args[0] - if plugin_name not in PLUGINS: - success = await load_plugin(plugin_name) - if success: - await bot.api.send_text_message(room.room_id, f"Plugin '{plugin_name}' loaded successfully") - else: - await bot.api.send_text_message(room.room_id, f"Failed to load plugin '{plugin_name}'") - else: - await bot.api.send_text_message(room.room_id, f"Plugin '{plugin_name}' is already loaded") - else: - await bot.api.send_text_message(room.room_id, "You are not authorized to load plugins.") diff --git a/plugins/disabled/plugins.py b/plugins/disabled/plugins.py deleted file mode 100644 index e239574..0000000 --- a/plugins/disabled/plugins.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -This plugin provides a command to list all loaded plugins along with their descriptions. -""" - -# plugins/plugins.py - -import os -import sys -import logging -import simplematrixbotlib as botlib - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !plugins command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("plugins"): - logging.info("Received !plugins command") - plugin_descriptions = get_plugin_descriptions() - - # Prepend custom string before the output - plugin_descriptions.insert(0, "# Plugins List: \n\n") - - plugins_message = "\n\n".join(plugin_descriptions) - await bot.api.send_markdown_message(room.room_id, plugins_message) - logging.info("Sent plugin list to the room") - - -def get_plugin_descriptions(): - """ - Function to get descriptions of all loaded plugin modules. - - Returns: - list: A list of plugin descriptions sorted alphabetically. - """ - plugin_descriptions = [] - for module_name, module in sys.modules.items(): - if module_name.startswith("plugins.") and hasattr(module, "__file__"): - plugin_path = module.__file__ - plugin_name = os.path.basename(plugin_path).split(".")[0] - try: - description = module.__doc__.strip().split("\n")[0] - except AttributeError: - description = "No description available" - plugin_descriptions.append(f"**[{plugin_name}.py]:** {description}") - - # Sort the plugin descriptions alphabetically by plugin name - plugin_descriptions.sort() - - return plugin_descriptions diff --git a/plugins/disabled/proxy.py b/plugins/disabled/proxy.py deleted file mode 100644 index a9b39ca..0000000 --- a/plugins/disabled/proxy.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -This plugin provides a command to get random SOCKS5 proxies. -""" - -# plugins/proxy.py - -import os -import logging -import random -import requests -import socket -import ssl -import time -from datetime import datetime, timedelta -import simplematrixbotlib as botlib - -# Constants -SOCKS5_LIST_URL = 'https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt' -MAX_TRIES = 5 -PROXY_LIST_FILENAME = 'socks5.txt' -PROXY_LIST_EXPIRATION = timedelta(hours=8) - -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: - ip, port = proxy.split(':') - start_time = time.time() - with socket.create_connection((ip, int(port)), timeout=5) as client: - client.sendall(b'\x05\x01\x00') - response = client.recv(2) - if response == b'\x05\x00': - latency = int(round((time.time() - start_time) * 1000, 0)) - logging.info(f"Successful connection to SOCKS5 proxy {proxy}. Latency: {latency} ms") - return True, latency - else: - logging.info(f"Failed to connect to SOCKS5 proxy {proxy}: Connection refused") - return False, None - except Exception as e: - logging.error(f"Error testing SOCKS5 proxy {proxy}: {e}") - return False, None - -async def download_proxy_list(): - """ - 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: - if not os.path.exists(PROXY_LIST_FILENAME) or \ - datetime.now() - datetime.fromtimestamp(os.path.getctime(PROXY_LIST_FILENAME)) > PROXY_LIST_EXPIRATION: - 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 - else: - logging.info("Proxy list already exists and is up-to-date") - return True - except Exception as e: - logging.error(f"Error downloading proxy list: {e}") - return False - - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle the !proxy command. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot, PREFIX) - if match.is_not_from_this_bot() and match.prefix() and match.command("proxy"): - 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: - # Read proxies from file - with open(PROXY_LIST_FILENAME, 'r') as f: - socks5_proxies = f.read().splitlines() - random.shuffle(socks5_proxies) - - # Test proxies - socks5_proxy = None - for proxy in socks5_proxies[:MAX_TRIES]: - success, latency = await test_socks5_proxy(proxy) - if success: - socks5_proxy = proxy - break - - # Send the first working anonymous proxy of each type to the Matrix room - if socks5_proxy: - await bot.api.send_markdown_message(room.room_id, f"✅ Anonymous SOCKS5 Proxy: **{socks5_proxy}** - Latency: **{latency} ms**") - logging.info(f"Sent SOCKS5 proxy {socks5_proxy} to the room") - else: - await bot.api.send_markdown_message(room.room_id, "❌ No working anonymous SOCKS5 proxy found") - logging.info("No working anonymous SOCKS5 proxy found") - - except Exception as e: - logging.error(f"Error handling !proxy command: {e}") - await bot.api.send_markdown_message(room.room_id, "❌ Error handling !proxy command") diff --git a/plugins/disabled/youtube.py b/plugins/disabled/youtube.py deleted file mode 100644 index 8357b10..0000000 --- a/plugins/disabled/youtube.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -This plugin provides a command to fetch YouTube video information from links. -""" - -# plugins/youtube.py - -import re -import logging -from pytube import YouTube -import simplematrixbotlib as botlib - -def seconds_to_minutes_seconds(seconds): - minutes = seconds // 60 - seconds %= 60 - return f"{minutes:02d}:{seconds:02d}" - -async def handle_command(room, message, bot, PREFIX): - """ - Function to handle YouTube video information from links. - - Args: - room (Room): The Matrix room where the command was invoked. - message (RoomMessage): The message object containing the command. - - Returns: - None - """ - match = botlib.MessageMatch(room, message, bot) - if match.is_not_from_this_bot() and re.search(r'youtube\.com/watch\?v=', message.body): - logging.info("YouTube link detected") - video_id_match = re.search(r'youtube\.com/watch\?v=([^\s]+)', message.body) - if video_id_match: - video_id = video_id_match.group(1) - youtube_url = f"https://www.youtube.com/watch?v={video_id}" - logging.info(f"Fetching information for YouTube video: {youtube_url}") - try: - video = YouTube(youtube_url) - title = video.title - description = video.description - length = seconds_to_minutes_seconds(video.length) - views = video.views - author = video.author - info_message = f"""**🎬🎝 Title:** {title} | **Length**: {length} minutes| **Views:** {views} | **Description:** {description}""" - await bot.api.send_markdown_message(room.room_id, info_message) - logging.info("Sent YouTube video information to the room") - except Exception as e: - logging.error(f"Error fetching YouTube video information: {str(e)}") - # await bot.api.send__message(room.room_id, "Error fetching YouTube video information.") diff --git a/plugins/load_plugin.py b/plugins/load_plugin.py index 2e5db54..2c650f3 100644 --- a/plugins/load_plugin.py +++ b/plugins/load_plugin.py @@ -5,9 +5,6 @@ import logging import importlib import simplematrixbotlib as botlib -# Bot configuration settings -ADMIN_USER = "@hashborgir:mozilla.org" - PLUGINS = {} async def load_plugin(plugin_name): @@ -20,10 +17,10 @@ async def load_plugin(plugin_name): logging.error(f"Error loading plugin {plugin_name}: {e}") return False -async def handle_command(room, message, bot, PREFIX, config): - match = botlib.MessageMatch(room, message, bot, PREFIX) +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("load"): - if str(message.sender) == ADMIN_USER: + if str(message.sender) == config.admin_user: args = match.args() if len(args) != 1: await bot.api.send_text_message(room.room_id, "Usage: !load ")