Skip to content

Level Design

Nicholas Springer edited this page Aug 30, 2019 · 1 revision

Level Creation Sections

This section of the guide will go through the three parts of implementing the create() function: initialization, deployment, and setup. When creating a level, we recommend starting from the template at levels/community/template. The template python module's create() has the 3 parts mapped out:

core/levels/community/template/template.py

from core.framework import levels
from core.framework.cloudhelpers import deployments

LEVEL_PATH = 'community/template'


def create():
    # Don't deploy the template. Delete this line when you implement your level.
    exit('This is a template file. It is not meant to be deployed.')

    # ---------Level Initialization---------
    # Put code here that generates anything passed to the configuration template,
    # sets up the project before deployment, or does anything else that happens
    # before the deployment gets inserted.

    # --------------------------------------

    # ---------Deployment Insertion---------
    # Insert the deployment, filling out labels, config template arguments,
    # and the deployment manager template imports.
    config_template_args = {}
    labels = {}
    template_files = []
    deployments.insert(LEVEL_PATH,
                       config_template_args=config_template_args,
                       labels=labels,
                       template_files=template_files)
    # --------------------------------------

    # --------------Level Setup-------------
    # Put code here that does anything that needs to happen after the deployment.
    # This includes usings APIs to modify deployed resources or anything else.

    # Print complete message and print/save start info
    print(f'Level creation complete for: {LEVEL_PATH}\n'
          f'Instruction for the level can be accessed at '
          f'thunder-ctf.cloud/levels/{LEVEL_PATH}.html')
    start_message = '--Put the start message here.--'
    levels.write_start_info(LEVEL_PATH, start_message)
    # --------------------------------------

Example Implementation

The rest of this section will explain the 3 parts in more detail and will show and describe how they were implemented in thunder/a1openbucket, a simple level that deploys a single public bucket with the secret inside the bucket in a file called secret.txt.

The full implementation of thunder/a1openbucket is shown below:

core/levels/thunder/a1openbucket/a1openbucket.py

import random

from google.cloud import storage

from core.framework import levels
from core.framework.cloudhelpers import deployments

LEVEL_PATH = 'thunder/a1openbucket'
RESOURCE_PREFIX = 'a1'


def create():
    # ---------Level Initialization---------
    # Create randomized bucket name to avoid namespace conflict
    nonce = str(random.randint(100000000000, 999999999999))
    bucket_name = f'{RESOURCE_PREFIX}-bucket-{nonce}'
    # --------------------------------------

    # ---------Deployment Insertion---------
    # Insert deployment
    config_template_args = {'nonce': nonce}
    template_files = ['core/framework/templates/bucket_acl.jinja']
    deployments.insert(LEVEL_PATH,
                       template_files=template_files,
                       config_template_args=config_template_args)
    # --------------------------------------

    # --------------Level Setup-------------
    print("Level setup started for: " + LEVEL_PATH)
    # Insert secret into bucket
    storage_client = storage.Client()
    bucket = storage_client.get_bucket(bucket_name)
    secret_blob = storage.Blob('secret.txt', bucket)
    secret = levels.make_secret(LEVEL_PATH)
    secret_blob.upload_from_string(secret)
    
    # Print complete message and print/save start info
    print(f'Level creation complete for: {LEVEL_PATH}\n'
          f'Instruction for the level can be accessed at thunder-ctf.cloud/levels/{LEVEL_PATH}.html')
    start_message = f'The secret for this level can be found in the Google Cloud Storage (GCS) bucket {bucket_name}'
    levels.write_start_info(LEVEL_PATH, start_message)
    # --------------------------------------