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

Updated the automation to fix the build issue (hopefully.) #2

Merged
merged 2 commits into from
Apr 21, 2024
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
2 changes: 1 addition & 1 deletion .automation/Read-Only/descriptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@
}
}
]
}
}
3 changes: 2 additions & 1 deletion .automation/Read-Only/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
httpx
chardet==4.0.0
httpx==0.27.0
179 changes: 127 additions & 52 deletions .automation/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,135 @@
import glob
import json
import httpx
import logging
import chardet

# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)

TOP_LEVEL_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
AUTOMATION_DIR = os.path.dirname(os.path.abspath(__file__))

DIRECTORY_LIST = [ y for y in glob.glob(os.path.join(TOP_LEVEL_DIR, '*')) if os.path.isdir(y) ]
DIRECTORY_LIST.sort()

SUB_DIRECTORY_LIST = [ y for x in DIRECTORY_LIST for y in glob.glob(os.path.join(x, '*')) if os.path.isdir(y) ]
SUB_DIRECTORY_LIST.sort()
# call the CTF Time API from the url in event.txt

with open(os.path.join(AUTOMATION_DIR, 'Change-Me/event.txt'), 'r') as f:
event_url = f.read()
# generate the api url from the event url
api_url = event_url.replace('ctftime.org/event/', 'ctftime.org/api/v1/events/')

# get the event description from the api url
r = httpx.get(api_url + '/')
event_description = r.json()['description']
event_name = r.json()['title']

# Open the descriptions file and read the descriptions into a list
with open(os.path.join(AUTOMATION_DIR, 'Read-Only/descriptions.json'), 'r') as f:
descriptions = json.load(f)

# generate the README.md file.
# generate an unordered list of the directories and subdirectories in the repository.
# should be in the format of:
# * [directory name](directory link)
# * [subdirectory name](subdirectory link)
# * [subdirectory name](subdirectory link)
# and so on...

with open(os.path.join(TOP_LEVEL_DIR, 'README.md'), 'w') as f:
f.write('# ' + event_name + '\n\n')
f.write(event_url + '\n\n')
f.write('## Event Description\n\n')
f.write(event_description + '\n\n')

def fetch_event_details(event_url):
try:
api_url = event_url.replace("ctftime.org/event/", "ctftime.org/api/v1/events/")
r = httpx.get(api_url + "/")
r.raise_for_status() # Raise an exception for non-2xx status codes
event_details = r.json()
return event_details["description"], event_details["title"]
except (httpx.HTTPError, json.JSONDecodeError, KeyError) as e:
logging.error(f"Error fetching event details: {e}")
return None, None


def read_descriptions(file_path):
try:
with open(file_path, "rb") as f:
result = chardet.detect(f.read())
encoding = result["encoding"]
with open(file_path, "r", encoding=encoding) as f:
descriptions = json.load(f)
return descriptions
except (FileNotFoundError, json.JSONDecodeError, UnicodeDecodeError) as e:
logging.error(f"Error reading descriptions file: {e}")
return None


def generate_readme(
event_name,
event_url,
event_description,
directory_list,
subdirectory_list,
descriptions,
output_path,
):
try:
with open(output_path, "w", encoding="utf-8") as f:
f.write(f"# {event_name}\n\n")
f.write(f"{event_url}\n\n")
f.write("## Event Description\n\n")
f.write(f"{event_description}\n\n")
for directory in directory_list:
directory_name = os.path.basename(directory)
f.write(f"## [{directory_name}](<{directory_name}/>)\n")
for subdirectory in subdirectory_list:
if os.path.dirname(subdirectory) == directory:
subdirectory_name = os.path.basename(subdirectory)
f.write(
f" * #### [{subdirectory_name}](<{directory_name}/{subdirectory_name}/>)\n"
)
except IOError as e:
logging.error(f"Error writing to {output_path}: {e}")


def main():
DIRECTORY_LIST = [
os.path.normpath(y)
for y in glob.glob(os.path.join(TOP_LEVEL_DIR, "*"))
if os.path.isdir(y)
]
DIRECTORY_LIST.sort()

SUB_DIRECTORY_LIST = [
os.path.normpath(y)
for x in DIRECTORY_LIST
for y in glob.glob(os.path.join(x, "*"))
if os.path.isdir(y)
]
SUB_DIRECTORY_LIST.sort()

event_file_path = os.path.join(AUTOMATION_DIR, "Change-Me", "event.txt")
descriptions_file_path = os.path.join(
AUTOMATION_DIR, "Read-Only", "descriptions.json"
)

try:
with open(event_file_path, "r") as f:
event_url = f.read().strip()
except FileNotFoundError:
logging.error(f"Event file '{event_file_path}' not found.")
return

event_description, event_name = fetch_event_details(event_url)
if event_description is None or event_name is None:
return

descriptions = read_descriptions(descriptions_file_path)
if descriptions is None:
return

top_level_readme_path = os.path.join(TOP_LEVEL_DIR, "README.md")
generate_readme(
event_name,
event_url,
event_description,
DIRECTORY_LIST,
SUB_DIRECTORY_LIST,
descriptions,
top_level_readme_path,
)

for directory in DIRECTORY_LIST:
f.write('## [{}](<{}>)\n'.format(os.path.basename(directory), os.path.basename(directory)))
for subdirectory in SUB_DIRECTORY_LIST:
if os.path.dirname(subdirectory) == directory:
f.write(' * #### [{}](<{}/{}/>)\n'.format(os.path.basename(subdirectory), os.path.basename(directory), os.path.basename(subdirectory) ))

# do the same thing for the README in each directory
for directory in DIRECTORY_LIST:
with open(os.path.join(directory, 'README.md'), 'w') as f:
f.write('# ' + os.path.basename(directory) + '\n\n')
# From the descriptions var, check if the directory name is contained in the category and if so, write the description to the README
f.write('### Category Description\n\n')
for category in descriptions['categories']:
if os.path.basename(directory) in category['name']:
f.write(category['details']['description'] + '\n\n')
f.write('## Challenges\n\n')
for subdirectory in SUB_DIRECTORY_LIST:
if os.path.dirname(subdirectory) == directory:
f.write('- ### [{}](<{}>)\n'.format(os.path.basename(subdirectory), os.path.basename(subdirectory)))
directory_readme_path = os.path.join(directory, "README.md")
with open(directory_readme_path, "w", encoding="utf-8") as f:
f.write(f"# {os.path.basename(directory)}\n\n")
f.write("### Category Description\n\n")
for category in descriptions["categories"]:
if os.path.basename(directory) in category["name"]:
f.write(f"{category['details']['description']}\n\n")
f.write("## Challenges\n\n")
for subdirectory in SUB_DIRECTORY_LIST:
if os.path.dirname(subdirectory) == directory:
f.write(
f"- ### [{os.path.basename(subdirectory)}](<{os.path.basename(subdirectory)}/>)\n"
)

logging.info("README files generated successfully.")


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion Crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ The word “cryptography” technically means the art of writing codes. When it

## Challenges

- ### [Example](<Example>)
- ### [Example](<Example/>)
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# MapleCTF 2023

https://ctftime.org/event/2038

## Event Description

Maple Bacon's jeopardy-style MapleCTF! Featuring challenges in web, pwn, rev, crypto and more.

## [Crypto](<Crypto>)
* #### [Example](<Crypto/Example/>)
## [Forensics](<Forensics>)
## [Misc](<Misc>)
## [OSINT](<OSINT>)
## [Pwn](<Pwn>)
## [Reverse](<Reverse>)
## [Steganography](<Steganography>)
## [Web](<Web>)
## [Blockchain](<Blockchain>)
# MapleCTF 2023

https://ctftime.org/event/2038

## Event Description

Maple Bacon's jeopardy-style MapleCTF! Featuring challenges in web, pwn, rev, crypto and more.


Thank you to our prizes sponsors – Zellic, Trail of Bits, HackerOne, Offensive Security, and Vector35! Infrastructure sponsored by GCP.

## [Blockchain](<Blockchain/>)
## [Crypto](<Crypto/>)
* #### [Example](<Crypto/Example/>)
## [Forensics](<Forensics/>)
## [Misc](<Misc/>)
## [OSINT](<OSINT/>)
## [Pwn](<Pwn/>)
## [Reverse](<Reverse/>)
## [Steganography](<Steganography/>)
## [Web](<Web/>)
Expand Down
Loading