Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ctf): store solves walkthrough #167

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
Open
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
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ [email protected]
OVISBOT_HTB_CREDS_PASS=myhtbpassword
OVISBOT_HTB_TEAM_ID=1000
OVISBOT_CTFTIME_TEAM_ID=999
OVISBOT_ADMIN_ROLE=moderator
OVISBOT_ADMIN_ROLE=moderator
OVISBOT_DB_URL=mongodb://localhost/ovisdb
OVISBOT_THIRD_PARTY_COGS_INSTALL_DIR=~/cogs
OVISBOT_CTFSOLVES_GITHUB_TOKEN=<github_token>
OVISBOT_CTFSOLVES_GITHUB_USER=<github_username>
OVISBOT_CTFSOLVES_GITHUB_REPO=<github_repo>
3 changes: 3 additions & 0 deletions ovisbot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ class Config(AbstractConfig):
DB_URL = environ.get("OVISBOT_DB_URL", "mongodb://mongo/ovisdb")
COMMAND_PREFIX = environ.get("OVISBOT_COMMAND_PREFIX", "!")
DISCORD_BOT_TOKEN = environ.get("OVISBOT_DISCORD_TOKEN")
GITHUB_CTFSOLVES_TOKEN = environ.get("OVISBOT_CTFSOLVES_GITHUB_TOKEN")
GITHUB_CTFSOLVES_USER = environ.get("OVISBOT_CTFSOLVES_GITHUB_USER")
GITHUB_CTFSOLVES_REPO = environ.get("OVISBOT_CTFSOLVES_GITHUB_REPO")

THIRD_PARTY_COGS_INSTALL_DIR = environ.get(
"OVISBOT_THIRD_PARTY_COGS_INSTALL_DIR", "/usr/local/share/ovisbot/cogs"
Expand Down
2 changes: 2 additions & 0 deletions ovisbot/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ class ChallengeExistsException(Exception):
class ChallengeInvalidCategory(Exception):
pass


class ChallengeInvalidDifficulty(Exception):
pass


class ChallengeAlreadySolvedException(Exception):
def __init__(self, solved_by, *args, **kwargs):
self.solved_by = solved_by
Expand Down
78 changes: 70 additions & 8 deletions ovisbot/extensions/ctf/ctf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import asyncio
import base64
import copy
import os
import discord
import datetime
import logging
Expand All @@ -8,6 +11,8 @@
import dateutil.parser
import pytz
import random
import json
import time

import ovisbot.locale as i18n

Expand Down Expand Up @@ -61,12 +66,7 @@
"htb",
]

CHALLENGE_DIFFICULTIES = [
"none",
"easy",
"medium",
"hard"
]
CHALLENGE_DIFFICULTIES = ["none", "easy", "medium", "hard"]

# difficulty -> (:emoji:, text)
DIFFICULTY_REWARDS = {
Expand All @@ -76,6 +76,7 @@
"hard": (":icecream:", "παωτόν"),
}


class Ctf(commands.Cog):
def __init__(self, bot):
self.bot = bot
Expand Down Expand Up @@ -117,6 +118,7 @@ async def status_error(self, ctx, error):

@ctf.command()
async def archive(self, ctx, ctf_name):
start = time.time()
"""
Arcive a CTF to the DB and remove it from discord
"""
Expand All @@ -127,10 +129,18 @@ async def archive(self, ctx, ctf_name):

if ctfrole is not None:
await ctfrole.delete()

for c in category.channels:
challenge = next((ch for ch in ctf.challenges if ch.name == c.name), None)
if challenge is not None:
await harvest_pins(c)
asyncio.ensure_future(self.push_to_github(ctf_name, c.name))

await c.delete()

await category.delete()

print(f"Took {(time.time() - start)} seconds to archive")
ctf.name = "__ARCHIVED__" + ctf.name # bug fix (==)
ctf.save()

Expand Down Expand Up @@ -366,7 +376,7 @@ async def finish_error(self, ctx, error):
@ctf.command()
async def solve(self, ctx):
"""
Marks the current challenge as solved by you.
Marks the current challenge as solved by you.
Addition of team mates that helped to solve is optional
"""
chall_name = ctx.channel.name
Expand Down Expand Up @@ -730,7 +740,7 @@ async def showcreds(self, ctx):
raise CTFSharedCredentialsNotSet
emb = discord.Embed(description=ctf.credentials(), colour=4387968)
await ctx.channel.send(embed=emb)

@showcreds.error
async def showcreds_error(self, ctx, error):
if isinstance(error, CTF.DoesNotExist):
Expand Down Expand Up @@ -955,6 +965,58 @@ async def check_reminders(self):
except CTF.DoesNotExist:
continue

k4rt0fl3r marked this conversation as resolved.
Show resolved Hide resolved
async def push_to_github(self, ctf_name, challenge_name):
pins_dir = f"{os.path.abspath(os.getcwd())}/pins/{challenge_name}/"
for filename in os.listdir(pins_dir):
user = self.bot.config_cls.GITHUB_CTFSOLVES_USER
repo = self.bot.config_cls.GITHUB_CTFSOLVES_REPO
url = f"https://api.github.com/repos/{user}/{repo}/contents/{ctf_name}/{challenge_name}/{filename}"
file = base64.b64encode(open(pins_dir + filename, "rb").read())
token = self.bot.config_cls.GITHUB_CTFSOLVES_TOKEN
message = json.dumps(
{
"message": f"store pins of challenge {challenge_name} from {ctf_name} ctf",
"branch": "master",
"content": file.decode("utf-8"),
}
)
resp = requests.put(
url,
data=message,
headers={
"Accept": "application/vnd.github.v3+json",
"Authorization": "token " + token,
},
)
os.remove(pins_dir + filename)
os.rmdir(pins_dir)


# Gathers all pinned messages and files in the /pins folder
async def harvest_pins(channel):
pins_dir = f"{os.path.abspath(os.getcwd())}/pins/{channel.name}"
os.makedirs(pins_dir)
complete_path = os.path.join(pins_dir, f"{channel.name}.md")
f = open(complete_path, "x")

pinned_messages = await channel.pins()

# reversed as to write first pinned message, first.
# otherwise, the last pinned message is the first to be written.
for pinned in reversed(pinned_messages):
f.write(pinned.content + os.linesep)

attachs = pinned.attachments
if len(attachs) != 0:
for a in attachs:
await a.save(os.path.join(pins_dir, a.filename))
file = f"[{a.filename}](./{a.filename})"
f.write(os.linesep + file + os.linesep)

f.write(os.linesep + "---" + os.linesep)

f.close()


def setup(bot):
bot.add_cog(Ctf(bot))
11 changes: 5 additions & 6 deletions ovisbot/extensions/ctftime/ctftime.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,25 @@ def rgb2hex(r, g, b):
)
await ctx.channel.send(embed=embed)

@ctftime.command( aliases = ["w"] )
@ctftime.command(aliases=["w"])
async def writeups(self, ctx, name):
"""
Returns the submitted writeups for a given CTF
!ctftime writeups <name>
!ctftime w <name>
"""
event = ctfh.Event( e_name = name )
event = ctfh.Event(e_name=name)
try:
ctf_name, ctf_writeups = event.find_event_writeups()
except ValueError:
await ctx.channel.send( "Could not find such event" )
await ctx.channel.send("Could not find such event")
return
writeups = '\n'.join(ctf_writeups)

writeups = "\n".join(ctf_writeups)
writeups = chunkify(writeups, 1700)
for chunk in writeups:
await ctx.channel.send(chunk)


@writeups.error
async def writeups_error(self, ctx, error):
if isinstance(error.original, ValueError):
Expand Down
Loading