#note to self: to convert existing ctf diaries, check whether `\n([0-9a-zA-Z]+)` (or `^((?:[a-zA-Z0-9] ?)+)\n- ` for some messier writeups) looks like a chall name, then replace with `\n### $1`
#remove all first level -s that i use for paragraph into 2 \ns
#push all ```s to the left without spaces
#TODO aggregate stats (total ctfs, total solves, solve and co-solve amt, category solves breakdown, avg chall per ctf?, avg points?, avg solve count??)
#exclude organized events
CWD = os.path.dirname(os.path.realpath(__file__))
alphanum = re.compile(r'[^A-Za-z0-9\- ]+')
merge_space = re.compile(r'\s+')
remove_formatting = lambda str: merge_space.sub('-', alphanum.sub('', str).strip()).lower() #for name formats
objects = {}
comments = {}
#read special events
with open(f'{CWD}/ctf-diary/special.yml', encoding='utf-8') as s:
objects.update(yaml.load(s, Loader=yaml.Loader))
#read all ctfs in record
skipped_cmts = []
for file in os.listdir(f'{CWD}/ctf-diary/ctfs'):
if file.endswith('.yml'):
name = file[:-4]
#read metadata into objects
with open(f'{CWD}/ctf-diary/ctfs/{file}', encoding='utf-8') as s:
#read comments; split according to headers ('### ') which should only be used by chall names, where the - is the start of comments
#the 3 ### should be good enough to differentiate headers from code comments, we will do sanity check when we actually map the comments anyway
try:
with open(f'{CWD}/ctf-diary/ctfs/comments/{name}.md', encoding='utf-8') as c:
assert c.read(4) == '### ' #the first line should already have a challenge, also discard the header
comments.update({name: {remove_formatting((sp:=v.split('\n', 1))[0]): sp[1] for v in c.read().split('\n### ')}})
except Exception as e:
skipped_cmts.append(name)
if 'challenges' in objects[name] and not all('writeup-url' in chall and chall['writeup-url'] for chall in objects[name]['challenges']): #only print if ctf should have comments
print(f'Cannot read comments for {file} ({type(e).__name__}), skipping...')
if 'challenges' in v else "<div class='text-center'>No specific challenges have been logged; It's all a team effort!</div>", #allow no challenge specified (e.g. A/D ctfs where its basically fully team effort so no specific challs that i wouldve fully solved)