Compare commits
No commits in common. "96edec466e40ca682bb37b6e2408b8334b3fe84b" and "0c00cea0704d934e5e67329382edbdfbb28f32f0" have entirely different histories.
96edec466e
...
0c00cea070
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.env
|
||||
.gitignore
|
||||
karma.db
|
||||
proxies.db
|
||||
proxy_lists/
|
||||
session.txt
|
||||
socks5.txt
|
||||
venv/
|
9
LICENSE
9
LICENSE
@ -1,9 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
81
README.md
81
README.md
@ -1,3 +1,80 @@
|
||||
# FunguyBot
|
||||
# Matrix Bot
|
||||
|
||||
Bot for the Matrix protocol/network using simplematrixbotlib
|
||||
Matrix Bot is a Python-based chat bot designed to work with Matrix, an open network for secure, decentralized communication. This bot is built using the `simplematrixbotlib` library and provides various commands and functionalities for interacting with Matrix rooms.
|
||||
|
||||
## Features
|
||||
|
||||
- Modular architecture: Commands are implemented as separate plugins, making it easy to add or modify functionality.
|
||||
- Command handling: The bot listens for specific commands prefixed with `!` and responds accordingly.
|
||||
- Plugin system: Each command is implemented as a separate plugin module, allowing for easy customization and extension.
|
||||
- Extensible: Users can add new commands by creating additional plugin modules.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone the repository:
|
||||
`git clone https://github.com/example/matrix-bot.git`
|
||||
|
||||
2. Install dependencies:
|
||||
`pip install -r requirements.txt`
|
||||
|
||||
3. Set up environment variables:
|
||||
Create a `.env` file in the root directory of the bot and add the following variables:
|
||||
|
||||
```
|
||||
MATRIX_URL="https://matrix.org" (or another homeserver)
|
||||
MATRIX_USER=""
|
||||
MATRIX_PASS=""
|
||||
```
|
||||
|
||||
4. Run the bot:
|
||||
|
||||
1. `python funguy.py`, or
|
||||
2. `chmod +x funguy.py`
|
||||
`./bot.py`
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
To use the bot, invite it to a Matrix room and interact with it by sending commands prefixed with `!`. For example:
|
||||
|
||||
- `!date`: Display the current date and time.
|
||||
- `!fortune`: Get a random fortune message.
|
||||
- `!proxy`: Retrieve and test random SOCKS5 and HTTP proxies.
|
||||
- `!isup <domain/ip>`: Check if the specified domain or IP address is reachable.
|
||||
- `!karma <user>`: View or modify karma points for a user.
|
||||
|
||||
For a complete list of available commands and their descriptions, use the `!commands` command.
|
||||
|
||||
# 🍄 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 Bot Credits 🌟
|
||||
|
||||
🧙♂️ Creator & Developer: Hash Borgir (HB): Hash Borgir, with a background in computer science and cybersecurity, is the author of 🍄Funguy Bot🍄.
|
||||
|
64
funguy.py
Executable file
64
funguy.py
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python
|
||||
# bot.py
|
||||
|
||||
import os
|
||||
import logging
|
||||
import importlib
|
||||
import simplematrixbotlib as botlib
|
||||
from dotenv import load_dotenv
|
||||
import time
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
# Bot configuration settings
|
||||
MATRIX_URL = os.getenv("MATRIX_URL")
|
||||
MATRIX_USER = os.getenv("MATRIX_USER")
|
||||
MATRIX_PASS = os.getenv("MATRIX_PASS")
|
||||
|
||||
ADMIN_USER = "@hashborgir:mozilla.org"
|
||||
|
||||
PREFIX = '!'
|
||||
|
||||
creds = botlib.Creds(MATRIX_URL, MATRIX_USER, MATRIX_PASS)
|
||||
bot = botlib.Bot(creds)
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO)
|
||||
|
||||
# Load plugins
|
||||
PLUGINS_DIR = "plugins"
|
||||
PLUGINS = {}
|
||||
|
||||
def load_plugins():
|
||||
for plugin_file in os.listdir(PLUGINS_DIR):
|
||||
if plugin_file.endswith(".py"):
|
||||
plugin_name = os.path.splitext(plugin_file)[0]
|
||||
try:
|
||||
module = importlib.import_module(f"{PLUGINS_DIR}.{plugin_name}")
|
||||
PLUGINS[plugin_name] = module
|
||||
logging.info(f"Loaded plugin: {plugin_name}")
|
||||
except Exception as e:
|
||||
logging.error(f"Error loading plugin {plugin_name}: {e}")
|
||||
|
||||
def reload_plugins():
|
||||
global PLUGINS
|
||||
PLUGINS = {}
|
||||
load_plugins()
|
||||
|
||||
load_plugins()
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def handle_commands(room, message):
|
||||
match = botlib.MessageMatch(room, message, bot, PREFIX)
|
||||
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.")
|
||||
|
||||
for plugin_name, plugin_module in PLUGINS.items():
|
||||
await plugin_module.handle_command(room, message, bot, PREFIX)
|
||||
|
||||
bot.run()
|
326
hcbot.py
Executable file
326
hcbot.py
Executable file
@ -0,0 +1,326 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import subprocess
|
||||
import sqlite3
|
||||
import time
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
from urllib.parse import urlparse
|
||||
import datetime
|
||||
import simplematrixbotlib as botlib
|
||||
import requests
|
||||
from pytube import YouTube
|
||||
import logging
|
||||
import inspect
|
||||
|
||||
|
||||
MATRIX_URL = "https://matrix.org"
|
||||
MATRIX_USER = "@hcbot:matrix.org"
|
||||
MATRIX_PASS = "W4iy$nt^qp~&$K~$w@@jEhnT"
|
||||
|
||||
creds = botlib.Creds(MATRIX_URL, MATRIX_USER, MATRIX_PASS)
|
||||
bot = botlib.Bot(creds)
|
||||
|
||||
PREFIX = '!'
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO)
|
||||
|
||||
# Database setup
|
||||
conn = sqlite3.connect('karma.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS karma
|
||||
(username TEXT PRIMARY KEY, points INTEGER)''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
async def ping_proxy(proxy):
|
||||
"""
|
||||
Ping a proxy server to check its availability.
|
||||
|
||||
Args:
|
||||
proxy (str): The proxy server address in the format 'ip:port'.
|
||||
|
||||
Returns:
|
||||
float or str: The ping time in milliseconds if the proxy is up, or 'N/A' if it's down.
|
||||
"""
|
||||
ip, port = proxy.split(':')
|
||||
start_time = time.time()
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(5)
|
||||
result = sock.connect_ex((ip, int(port)))
|
||||
if result == 0:
|
||||
return round((time.time() - start_time) * 1000, 2)
|
||||
except Exception as e:
|
||||
logging.error(f"Error pinging proxy {proxy}: {e}")
|
||||
return "N/A"
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def commands(room, message):
|
||||
"""
|
||||
Command to display the list of available commands and their descriptions.
|
||||
|
||||
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 = """
|
||||
**Available Commands:**
|
||||
|
||||
**!fortune**
|
||||
Returns a random fortune message.
|
||||
|
||||
**!date**
|
||||
Displays the current date and time.
|
||||
|
||||
**!proxy**
|
||||
Retrieves and tests random SOCKS5 and HTTP proxies.
|
||||
|
||||
**!isup <domain/ip>**
|
||||
Checks if the specified domain or IP address is reachable.
|
||||
|
||||
**!karma <user>**
|
||||
Retrieves the karma points for the specified user.
|
||||
|
||||
**!karma <user> up**
|
||||
Increases the karma points for the specified user by 1.
|
||||
|
||||
**!karma <user> down**
|
||||
Decreases the karma points for the specified user by 1.
|
||||
"""
|
||||
await bot.api.send_markdown_message(room.room_id, commands_message)
|
||||
logging.info("Sent commands documentation to the room")
|
||||
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def fortune(room, message):
|
||||
"""
|
||||
Command to get a random fortune.
|
||||
|
||||
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_text_message(room.room_id, fortune_output)
|
||||
logging.info("Sent fortune to the room")
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def date(room, message):
|
||||
"""
|
||||
Command to get the current date and time.
|
||||
|
||||
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")
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def proxy(room, message):
|
||||
"""
|
||||
Command to get random SOCKS5 and HTTP proxies.
|
||||
|
||||
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")
|
||||
socks5_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/socks5.txt').text.splitlines()
|
||||
http_proxies = requests.get('https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/http.txt').text.splitlines()
|
||||
|
||||
random_socks5_proxy = random.choice(socks5_proxies)
|
||||
random_http_proxy = random.choice(http_proxies)
|
||||
|
||||
socks5_ping = await ping_proxy(random_socks5_proxy)
|
||||
http_ping = await ping_proxy(random_http_proxy)
|
||||
|
||||
await bot.api.send_text_message(room.room_id, f"Random SOCKS5 Proxy: {random_socks5_proxy} - Ping time: {socks5_ping} ms")
|
||||
await bot.api.send_text_message(room.room_id, f"Random HTTP Proxy: {random_http_proxy} - Ping time: {http_ping} ms")
|
||||
logging.info("Sent proxies to the room")
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def isup(room, message):
|
||||
"""
|
||||
Command to check if a website or server is up.
|
||||
|
||||
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_text_message(room.room_id, "Usage: !isup <ipv4/ipv6/domain>")
|
||||
logging.info("Sent usage message to the room")
|
||||
return
|
||||
|
||||
target = args[0]
|
||||
try:
|
||||
response = os.system(f"ping -c 1 {target}")
|
||||
if response == 0:
|
||||
await bot.api.send_text_message(room.room_id, f"{target} is up")
|
||||
else:
|
||||
await bot.api.send_text_message(room.room_id, f"{target} is down")
|
||||
logging.info(f"Sent status of {target} to the room")
|
||||
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}")
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def karma(room, message):
|
||||
"""
|
||||
Command to manage karma points for users.
|
||||
|
||||
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,))
|
||||
points = c.fetchone()[0]
|
||||
conn.close()
|
||||
await bot.api.send_text_message(room.room_id, f"{sender}'s karma points: {points}")
|
||||
logging.info(f"Sent {sender}'s karma points ({points}) to the room")
|
||||
elif len(args) == 1:
|
||||
username = args[0]
|
||||
|
||||
if username == sender:
|
||||
await bot.api.send_text_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,))
|
||||
points = c.fetchone()[0]
|
||||
conn.close()
|
||||
await bot.api.send_text_message(room.room_id, f"{username}'s karma points: {points}")
|
||||
logging.info(f"Sent {username}'s karma points ({points}) to the room")
|
||||
elif len(args) == 2:
|
||||
username, action = args
|
||||
if action not in ['up', 'down']:
|
||||
await bot.api.send_text_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_text_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('''UPDATE karma SET points = points + 1 WHERE username = ?''', (username,))
|
||||
else:
|
||||
c.execute('''UPDATE karma SET points = points - 1 WHERE username = ?''', (username,))
|
||||
|
||||
conn.commit()
|
||||
c.execute('''SELECT points FROM karma WHERE username = ?''', (username,))
|
||||
points = c.fetchone()[0]
|
||||
conn.close()
|
||||
|
||||
await bot.api.send_text_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_text_message(room.room_id, "Usage: !karma [username] [up/down]")
|
||||
logging.info("Sent usage message to the room")
|
||||
|
||||
|
||||
import re
|
||||
|
||||
@bot.listener.on_message_event
|
||||
async def youtube(room, message):
|
||||
"""
|
||||
Command to fetch 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 = video.length
|
||||
views = video.views
|
||||
author = video.author
|
||||
info_message = f"""Title: {title} | Length: {length} seconds | 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_text_message(room.room_id, "Error fetching YouTube video information.")
|
||||
|
||||
|
||||
bot.run()
|
70
plugins/commands.py
Normal file
70
plugins/commands.py
Normal file
@ -0,0 +1,70 @@
|
||||
# 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 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🍄.
|
||||
|
||||
"""
|
||||
await bot.api.send_markdown_message(room.room_id, commands_message)
|
||||
logging.info("Sent commands documentation to the room")
|
28
plugins/date.py
Normal file
28
plugins/date.py
Normal file
@ -0,0 +1,28 @@
|
||||
# plugins/date.py
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import simplematrixbotlib as botlib
|
||||
|
||||
async def handle_command(room, message, bot, 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")
|
23
plugins/fortune.py
Normal file
23
plugins/fortune.py
Normal file
@ -0,0 +1,23 @@
|
||||
# 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")
|
83
plugins/isup.py
Normal file
83
plugins/isup.py
Normal file
@ -0,0 +1,83 @@
|
||||
# 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 <ipv4/ipv6/domain>")
|
||||
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")
|
101
plugins/karma.py
Normal file
101
plugins/karma.py
Normal file
@ -0,0 +1,101 @@
|
||||
# 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")
|
116
plugins/proxy.py
Normal file
116
plugins/proxy.py
Normal file
@ -0,0 +1,116 @@
|
||||
# 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")
|
39
plugins/youtube.py
Normal file
39
plugins/youtube.py
Normal file
@ -0,0 +1,39 @@
|
||||
# plugins/youtube.py
|
||||
|
||||
import re
|
||||
import logging
|
||||
from pytube import YouTube
|
||||
import simplematrixbotlib as botlib
|
||||
|
||||
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 = video.length
|
||||
views = video.views
|
||||
author = video.author
|
||||
info_message = f"""**🎬🎝 Title:** {title} | **Length**: {length} sec | **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.")
|
36
requirements.txt
Normal file
36
requirements.txt
Normal file
@ -0,0 +1,36 @@
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.9.3
|
||||
aiohttp-socks==0.7.1
|
||||
aiosignal==1.3.1
|
||||
async-timeout==4.0.3
|
||||
attrs==23.2.0
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
cryptography==42.0.2
|
||||
frozenlist==1.4.1
|
||||
h11==0.14.0
|
||||
h2==4.1.0
|
||||
hpack==4.0.0
|
||||
hyperframe==6.0.1
|
||||
idna==3.6
|
||||
jsonschema==4.21.1
|
||||
jsonschema-specifications==2023.12.1
|
||||
Markdown==3.5.2
|
||||
matrix-nio==0.23.0
|
||||
multidict==6.0.5
|
||||
pillow==10.2.0
|
||||
pycparser==2.21
|
||||
pycryptodome==3.20.0
|
||||
python-cryptography-fernet-wrapper==1.0.4
|
||||
python-dotenv==1.0.1
|
||||
python-socks==2.4.4
|
||||
pytube==15.0.0
|
||||
referencing==0.33.0
|
||||
requests==2.31.0
|
||||
rpds-py==0.17.1
|
||||
simplematrixbotlib==2.10.3
|
||||
toml==0.10.2
|
||||
unpaddedbase64==2.1.0
|
||||
urllib3==2.2.0
|
||||
yarl==1.9.4
|
Loading…
Reference in New Issue
Block a user