From 864523f9542554c215ad002a078a4e558a33f69f Mon Sep 17 00:00:00 2001 From: Minh Duong Date: Fri, 30 Aug 2024 16:18:20 -0500 Subject: [PATCH] Add config file and private roles (#32) * Add config file support * Add roles cog * Move into `src` folder and update docker build * Add additional config options --- .gitignore | 3 + Dockerfile | 2 +- docker-compose.yml | 3 + lib/config.py | 11 ---- requirements.txt | 1 - {cogs => src/cogs}/chal/chal.py | 0 {cogs => src/cogs}/copypasta/copypasta.csv | 0 {cogs => src/cogs}/copypasta/copypasta.py | 0 {cogs => src/cogs}/ctf/ctf.py | 0 {cogs => src/cogs}/ctfs/ctfs.py | 0 {cogs => src/cogs}/manager/manager.py | 0 src/cogs/roles/roles.py | 73 ++++++++++++++++++++++ {cogs => src/cogs}/template/template.py | 0 src/lib/config.py | 27 ++++++++ {lib => src/lib}/util.py | 0 main.py => src/main.py | 0 src/requirements.txt | 2 + 17 files changed, 109 insertions(+), 13 deletions(-) delete mode 100644 lib/config.py delete mode 100644 requirements.txt rename {cogs => src/cogs}/chal/chal.py (100%) rename {cogs => src/cogs}/copypasta/copypasta.csv (100%) rename {cogs => src/cogs}/copypasta/copypasta.py (100%) rename {cogs => src/cogs}/ctf/ctf.py (100%) rename {cogs => src/cogs}/ctfs/ctfs.py (100%) rename {cogs => src/cogs}/manager/manager.py (100%) create mode 100644 src/cogs/roles/roles.py rename {cogs => src/cogs}/template/template.py (100%) create mode 100644 src/lib/config.py rename {lib => src/lib}/util.py (100%) rename main.py => src/main.py (100%) create mode 100644 src/requirements.txt diff --git a/.gitignore b/.gitignore index fe1fa01..36c5741 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ debug* *.sw* __pycache__/ .vscode/ + +# config file +config.yml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5e4fc7a..399585a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM python:3.10 # Change into the source directory WORKDIR /bot -COPY . . +COPY src . RUN pip install -r requirements.txt diff --git a/docker-compose.yml b/docker-compose.yml index 947c3f0..38e51b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,3 +9,6 @@ services: - CTF_CATEGORY_CHANNELS - CTF_ROLES - UIUC_ROLES + volumes: + - ./.env:/bot/.env + - ./config.yml:/bot/config.yml diff --git a/lib/config.py b/lib/config.py deleted file mode 100644 index 4fb0434..0000000 --- a/lib/config.py +++ /dev/null @@ -1,11 +0,0 @@ -import os - - -DISCORD_TOKEN = os.getenv('DISCORD_TOKEN') -GUILD_IDS = os.getenv('GUILD_IDS', "").split(",") -CTF_CATEGORY_CHANNELS = os.getenv("CTF_CATEGORY_CHANNELS", "").split(",") -CTF_ROLES = os.getenv("CTF_ROLES", "").split(",") -UIUC_ROLES = os.getenv("UIUC_ROLES", "").split(",") - -CHALLENGE_CATEGORIES = ["crypto", "forensics", "misc", "pwn", "osint", "rev", "web"] -FORUM_GENERAL_CHANNEL = "General" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 2314212..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -discord-py-interactions==5.11.0 \ No newline at end of file diff --git a/cogs/chal/chal.py b/src/cogs/chal/chal.py similarity index 100% rename from cogs/chal/chal.py rename to src/cogs/chal/chal.py diff --git a/cogs/copypasta/copypasta.csv b/src/cogs/copypasta/copypasta.csv similarity index 100% rename from cogs/copypasta/copypasta.csv rename to src/cogs/copypasta/copypasta.csv diff --git a/cogs/copypasta/copypasta.py b/src/cogs/copypasta/copypasta.py similarity index 100% rename from cogs/copypasta/copypasta.py rename to src/cogs/copypasta/copypasta.py diff --git a/cogs/ctf/ctf.py b/src/cogs/ctf/ctf.py similarity index 100% rename from cogs/ctf/ctf.py rename to src/cogs/ctf/ctf.py diff --git a/cogs/ctfs/ctfs.py b/src/cogs/ctfs/ctfs.py similarity index 100% rename from cogs/ctfs/ctfs.py rename to src/cogs/ctfs/ctfs.py diff --git a/cogs/manager/manager.py b/src/cogs/manager/manager.py similarity index 100% rename from cogs/manager/manager.py rename to src/cogs/manager/manager.py diff --git a/src/cogs/roles/roles.py b/src/cogs/roles/roles.py new file mode 100644 index 0000000..29c2ae4 --- /dev/null +++ b/src/cogs/roles/roles.py @@ -0,0 +1,73 @@ +import interactions +from interactions import Extension, SlashContext + +from lib.util import subcommand +from lib.config import UIUC_ROLES, PRIVATE_ROLES + + +class Roles(Extension): + '''Commands for managing private roles''' + + def __init__(self, _): + self.roles = PRIVATE_ROLES + + @subcommand(role={"description": "Role to add","autocomplete": True}) + async def add(self, ctx: SlashContext, role: str) -> None: + """Add a private role. Requires the UIUC role.""" + if (ctx.guild == None): + await ctx.send(":x: You can only run this command in a server.") + return + user = ctx.guild.get_member(ctx.user.id) + if (user == None): + await ctx.send(":x: You aren't in the server! Are you a ghost?") + return + if (not any(user.has_role(role) for role in UIUC_ROLES)): + await ctx.send(":x: You need to be UIUC verified to use this command. Verify yourself at .") + for valid_role in self.roles: + valid_role_name = valid_role.get("name") + valid_role_id = valid_role.get("discord_role_id") + if not valid_role_name or not valid_role_id: + continue + if role == valid_role_name: + if user.has_role(valid_role_id): + await ctx.send(f":x: You already have the **{role}** role.") + return + await user.add_role(valid_role_id) + await ctx.send(f":white_check_mark: Added you to **{role}**.") + return + await ctx.send(":x: Invalid role.") + + @subcommand(role={"description": "Role to remove","autocomplete": True}) + async def remove(self, ctx: SlashContext, role: str) -> None: + """Removes a private role.""" + if (ctx.guild == None): + await ctx.send(":x: You can only run this command in a server.") + return + user = ctx.guild.get_member(ctx.user.id) + if (user == None): + await ctx.send(":x: You aren't in the server! Are you a ghost?") + return + for valid_role in self.roles: + valid_role_name = valid_role.get("name") + valid_role_id = valid_role.get("discord_role_id") + if not valid_role_name or not valid_role_id: + continue + if role == valid_role_name: + if not user.has_role(valid_role_id): + await ctx.send(f":x: You do not have the **{role}** role.") + return + await user.remove_role(valid_role_id) + await ctx.send(f":white_check_mark: Removed you from **{role}**.") + return + await ctx.send(":x: Invalid role.") + + @add.autocomplete("role") + @remove.autocomplete("role") + async def find_role(self, ctx: interactions.AutocompleteContext): + current_input = ctx.kwargs.get("role") + autocomplete_options = [] + for valid_role in self.roles: + valid_role_name = valid_role.get("name") + if valid_role_name and current_input in valid_role_name: + autocomplete_options.append(valid_role_name) + await ctx.send(autocomplete_options[:25]) diff --git a/cogs/template/template.py b/src/cogs/template/template.py similarity index 100% rename from cogs/template/template.py rename to src/cogs/template/template.py diff --git a/src/lib/config.py b/src/lib/config.py new file mode 100644 index 0000000..c1d51af --- /dev/null +++ b/src/lib/config.py @@ -0,0 +1,27 @@ +import os +import yaml +import logging + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +config = {} +try: + with open("config.yml", "r") as f: + try: + config = yaml.safe_load(f) + except yaml.YAMLError as e: + logger.error(f"Error loading config: {e}") + exit(1) +except FileNotFoundError: + logger.warning("No config file found.") + +DISCORD_TOKEN = os.getenv('DISCORD_TOKEN') or config.get("discord_token") +GUILD_IDS = os.getenv('GUILD_IDS', "").split(",") or config.get("guild_ids", []) +CTF_CATEGORY_CHANNELS = os.getenv("CTF_CATEGORY_CHANNELS", "").split(",") or config.get("ctf_category_channels", []) +CTF_ROLES = os.getenv("CTF_ROLES", "").split(",") or config.get("ctf_roles", []) +UIUC_ROLES = os.getenv("UIUC_ROLES", "").split(",") or config.get("uiuc_roles", []) +PRIVATE_ROLES = config.get("private_roles", []) + +CHALLENGE_CATEGORIES = ["crypto", "forensics", "misc", "pwn", "osint", "rev", "web"] +FORUM_GENERAL_CHANNEL = "General" diff --git a/lib/util.py b/src/lib/util.py similarity index 100% rename from lib/util.py rename to src/lib/util.py diff --git a/main.py b/src/main.py similarity index 100% rename from main.py rename to src/main.py diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..c4aea58 --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,2 @@ +discord-py-interactions==5.11.0 +PyYAML==6.0.2 \ No newline at end of file