Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions .github/workflows/DiscordBot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,35 @@ jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Set up QEMU
uses: docker/setup-qemu-action@v1

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1


- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: plop91/plop_discord
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-

- name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_SECRET }}

- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: plop91/plop_discord:nightly
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
139 changes: 68 additions & 71 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -1,71 +1,68 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '23 1 * * 1'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed

steps:
- name: Checkout repository
uses: actions/checkout@v2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
pull_request:
schedule:
- cron: '23 1 * * 1'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed

steps:
- name: Checkout repository
uses: actions/checkout@v2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
26 changes: 24 additions & 2 deletions BotHead.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,31 @@ async def setup_hook(self) -> None:
Setup hook for the bot, loads all cogs.
:return: None
"""
for f in os.listdir('./cogs'):
cogs_dir = './cogs'
if not os.path.exists(cogs_dir):
settings.logger.error(f"Cogs directory '{cogs_dir}' does not exist. Cannot load cogs.")
return

if not os.path.isdir(cogs_dir):
settings.logger.error(f"'{cogs_dir}' exists but is not a directory. Cannot load cogs.")
return

try:
cog_files = os.listdir(cogs_dir)
except PermissionError:
settings.logger.error(f"Permission denied reading cogs directory '{cogs_dir}'")
return
except OSError as e:
settings.logger.error(f"Error reading cogs directory '{cogs_dir}': {e}")
return

for f in cog_files:
if f.endswith('.py'):
await self.load_extension(f'cogs.{f[:-3]}')
try:
await self.load_extension(f'cogs.{f[:-3]}')
settings.logger.info(f"Loaded cog: {f[:-3]}")
except Exception as e:
settings.logger.error(f"Failed to load cog {f[:-3]}: {e}")

# @commands.command(brief="Admin only command: Load a Cog.")
# async def load(self, ctx, extension):
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RUN git clone https://github.com/plop91/PlopBot.git
# Set working dir to the git repo
WORKDIR /usr/src/app/PlopBot/
# Set branch to pull from
ARG branch=devel
ARG branch=ian-nightly
# fetch branchs
RUN git fetch
# Checkout branch
Expand Down
94 changes: 79 additions & 15 deletions cogs/adminCog.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
from discord.ext import commands
import settings
import subprocess


class Admin(commands.Cog):
Expand Down Expand Up @@ -32,7 +33,34 @@ async def hash(self, ctx):
:arg ctx: context of the command
:return: None
"""
pass
# Use Discord user IDs instead of string names to prevent spoofing
admin_ids = settings.info_json.get("admin_ids", [])
# Fallback to old string-based check if admin_ids not configured
admin_strings = settings.info_json.get("admins", [])
is_admin = ctx.author.id in admin_ids or str(ctx.author) in admin_strings

if is_admin:
try:
# Get the current git commit hash
result = subprocess.run(
['git', 'rev-parse', '--short', 'HEAD'],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
commit_hash = result.stdout.strip()
await ctx.send(f"Current commit hash: `{commit_hash}`")
else:
await ctx.send("Failed to get git commit hash")
except subprocess.TimeoutExpired:
await ctx.send("Git command timed out")
except Exception as e:
settings.logger.error(f"Error getting git hash: {e}")
await ctx.send("Error retrieving git commit hash")
else:
await ctx.send("You do not have permission to run this command")
settings.logger.warning(f"Unauthorized hash command attempt by {ctx.author}")

@commands.command(brief="Admin only command: provide current version")
async def version(self, ctx):
Expand All @@ -41,7 +69,33 @@ async def version(self, ctx):
:arg ctx: context of the command
:return: None
"""
pass
# Use Discord user IDs instead of string names to prevent spoofing
admin_ids = settings.info_json.get("admin_ids", [])
admin_strings = settings.info_json.get("admins", [])
is_admin = ctx.author.id in admin_ids or str(ctx.author) in admin_strings

if is_admin:
try:
# Try to get version from git tag
result = subprocess.run(
['git', 'describe', '--tags', '--always'],
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
version = result.stdout.strip()
await ctx.send(f"Bot version: `{version}`")
else:
await ctx.send("Version information not available")
except subprocess.TimeoutExpired:
await ctx.send("Git command timed out")
except Exception as e:
settings.logger.error(f"Error getting version: {e}")
await ctx.send("Error retrieving version information")
else:
await ctx.send("You do not have permission to run this command")
settings.logger.warning(f"Unauthorized version command attempt by {ctx.author}")

@commands.command(brief="Admin only command: Turn the bot off.")
async def kill(self, ctx):
Expand All @@ -50,41 +104,51 @@ async def kill(self, ctx):
:arg ctx: context of the command
:return: None
"""
# Use Discord user IDs instead of string names to prevent spoofing
admin_ids = settings.info_json.get("admin_ids", [])
admin_strings = settings.info_json.get("admins", [])
is_admin = ctx.author.id in admin_ids or str(ctx.author) in admin_strings

# try to gracefully shut down the bot
# noinspection PyBroadException
try:
if str(ctx.author) in settings.info_json["admins"]:
if is_admin:
settings.logger.info(f"kill from {ctx.author}!")
if str(ctx.message.channel) in settings.info_json["command_channels"]:
await self.client.logout()
await self.client.close()
else:
await ctx.channel.send(ctx.author)
await ctx.channel.send(settings.info_json["admins"])
await ctx.channel.send("you are not an admin")
# if the bot fails to log out kill it
await ctx.channel.send("You do not have permission to run this command")
settings.logger.warning(f"Unauthorized kill attempt by {ctx.author}")
# if the bot fails to close kill it
except Exception:
exit(1)

@commands.command(brief="Admin only command: Restart the bot.")
async def restart(self, ctx):
"""
Preforms a restart of the bot
Note: This command closes the bot. The bot should be managed by a process manager
(like systemd or docker) that will automatically restart it.
:arg ctx: context of the command
:return: None
"""
# Use Discord user IDs instead of string names to prevent spoofing
admin_ids = settings.info_json.get("admin_ids", [])
admin_strings = settings.info_json.get("admins", [])
is_admin = ctx.author.id in admin_ids or str(ctx.author) in admin_strings

# try to gracefully shut down the bot
# noinspection PyBroadException
try:
if str(ctx.author) in settings.info_json["admins"]:
if is_admin:
settings.logger.info(f"restart from {ctx.author}!")
if str(ctx.message.channel) in settings.info_json["command_channels"]:
await self.client.logout()
await self.client.start(settings.info_json["token"])
await ctx.send("Restarting bot... (requires process manager)")
await self.client.close()
else:
await ctx.channel.send(ctx.author)
await ctx.channel.send(settings.info_json["admins"])
await ctx.channel.send("you are not an admin")
# if the bot fails to log out kill it
await ctx.channel.send("You do not have permission to run this command")
settings.logger.warning(f"Unauthorized restart attempt by {ctx.author}")
# if the bot fails to close kill it
except Exception:
exit(1)

Expand Down
Loading
Loading