Project Stepwise
Project Stepwise
The time it will take can vary based on your familiarity with programming
and the specific features you want. Here’s a rough breakdown:
Learning Basics (if needed): 1-2 weeks (if you're starting from
scratch)
Print Statement:
python
Copy code
print("Hello, World!")
Variables:
python
Copy code
name = "Alice"
age = 30
2. Data Types
3. Lists
python
Copy code
fruits = ["apple", "banana", "cherry"]
4. Tuples
python
Copy code
coordinates = (10.0, 20.0)
5. Dictionaries
Key-value pairs.
python
Copy code
person = {"name": "Alice", "age": 30}
6. Control Flow
If Statements:
python
Copy code
if age >= 18:
print("Adult")
else:
print("Minor")
Loops:
o For Loop:
python
Copy code
for fruit in fruits:
print(fruit)
o While Loop:
python
Copy code
count = 0
while count < 5:
print(count)
count += 1
7. Functions
python
Copy code
def greet(name):
return f"Hello, {name}!"
print(greet("Alice"))
python
Copy code
import math
print(math.sqrt(16))
9. File Handling
python
Copy code
with open("file.txt", "w") as file:
file.write("Hello, World!")
Understand CTFd (Overview of CTFd)
CTFd is an open-source Capture The Flag (CTF) platform that allows you to host and
manage CTF competitions. It’s built with Python and Flask, and it uses a SQL database to
store data.
1. Installation:
o To start using CTFd, you'll first need to set it up. You can follow the CTFd
installation guide.
2. Understanding the Structure:
o CTFd has a specific folder structure, with key directories including:
CTFd/: Main application folder.
CTFd/plugins/: Where you will place your custom plugins.
CTFd/models/: Contains database models for the platform.
3. Creating a Plugin:
o Plugins are Python scripts that enhance CTFd's functionality. A basic plugin
might look like this:
python
Copy code
from CTFd.plugins import Plugin
class MyPlugin(Plugin):
def __init__(self):
super().__init__()
def load(self):
# Code to run when the plugin is loaded
pass
def load(app):
return MyPlugin()
python
Copy code
import requests
def get_challenges():
response = requests.get("http://your-ctfd-url/api/v1/challenges")
return response.json()
5. Database Interactions:
o CTFd uses SQLAlchemy for database interactions. You can create or query
data using models.
python
Copy code
from CTFd.models import db, Challenges
def get_all_challenges():
return Challenges.query.all()
Explore OpenStack
OpenStack is a cloud computing platform that allows you to manage and deploy resources
such as virtual machines, networks, and storage. It has a modular architecture, consisting of
various services like Nova (compute), Neutron (networking), and Swift (storage).
1. Authentication:
o Before interacting with the OpenStack API, you need to authenticate. This
usually involves obtaining an access token from the Identity service
(Keystone).
o Example of authentication:
python
Copy code
import requests
auth_url = "http://your-openstack-url:5000/v3/auth/tokens"
headers = {'Content-Type': 'application/json'}
data = {
"auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "your_username",
"domain": {"id": "default"},
"password": "your_password"
}
}
}
}
}
python
Copy code
nova_url = "http://your-openstack-url:8774/v2.1/servers"
headers = {'X-Auth-Token': token}
o Neutron (Networking):
To list networks:
python
Copy code
neutron_url = "http://your-openstack-url:9696/v2.0/networks"
response = requests.get(neutron_url, headers=headers)
networks = response.json()
3. Common Operations:
o Creating an Instance:
python
Copy code
create_instance_data = {
"server": {
"name": "my-instance",
"imageRef": "image_id",
"flavorRef": "flavor_id",
"networks": [{"uuid": "network_id"}]
}
}
nova_create_url =
f"http://your-openstack-url:8774/v2.1/servers"
response = requests.post(nova_create_url,
json=create_instance_data, headers=headers)
o Deleting an Instance:
python
Copy code
instance_id = "your_instance_id"
nova_delete_url =
f"http://your-openstack-url:8774/v2.1/servers/{instance_id}"
response = requests.delete(nova_delete_url, headers=headers)
OpenStack Documentation
OpenStack SDK for Python: This is a more user-friendly way to interact with
OpenStack APIs.
bash
Copy code
pip install openstacksdk
Example usage:
python
Copy code
import openstack
conn =
openstack.connect(auth_url='http://your-openstack-url:5000/v3',
project_name='your_project',
username='your_username',
password='your_password',
user_domain_id='default',
project_domain_id='default')
# List instances
instances = conn.compute.servers()
for instance in instances:
print(instance.name)
Summary
By understanding how to authenticate and interact with the OpenStack API, you’ll be able to
integrate OpenStack functionalities into your CTFd plugin effectively.
Start Developing the Plugin
Let’s get started on developing your CTFd plugin that interacts with OpenStack. I’ll guide
you through the basic steps, including setting up your environment and writing the code for
your plugin.
1. Install CTFd:
o Follow the CTFd installation guide to set up CTFd locally.
2. Install Dependencies:
o Make sure you have Python and pip installed. You might need additional
libraries for OpenStack, like openstacksdk.
bash
Copy code
pip install openstacksdk
bash
Copy code
CTFd/plugins/my_openstack_plugin
1. Create __init__.py:
o Inside your plugin folder, create an __init__.py file. This file will define
your plugin.
python
Copy code
from CTFd.plugins import Plugin
class MyOpenStackPlugin(Plugin):
def __init__(self):
super().__init__()
def load(self):
# Code to run when the plugin is loaded
pass
def load(app):
return MyOpenStackPlugin()
2. Set Up Configuration (if needed):
o You may want to create a configuration file for OpenStack credentials. This
can be done using a JSON or YAML file.
Here’s an example of a simple plugin that lists OpenStack instances when loaded:
python
Copy code
import json
def load_credentials():
with open("path/to/your/credentials.json") as f:
return json.load(f)
2. Connect to OpenStack:
python
Copy code
import openstack
def connect_to_openstack(creds):
return openstack.connect(
auth_url=creds['auth_url'],
project_name=creds['project_name'],
username=creds['username'],
password=creds['password'],
user_domain_id='default',
project_domain_id='default'
)
3. List Instances:
python
Copy code
def list_instances(conn):
instances = conn.compute.servers()
return [instance.name for instance in instances]
4. Complete Plugin Code: Here’s how your __init__.py might look with these
functions:
python
Copy code
from CTFd.plugins import Plugin
import openstack
import json
class MyOpenStackPlugin(Plugin):
def __init__(self):
super().__init__()
def load(self):
creds = load_credentials()
conn = connect_to_openstack(creds)
instances = list_instances(conn)
print("OpenStack Instances:", instances)
def load(app):
return MyOpenStackPlugin()
Once the basic functionality is working, you can extend your plugin with additional features:
Summary
You now have a basic structure for your CTFd plugin that interacts with OpenStack.
Architecture
CTFd plugins are implemented as Python modules with some CTFd specific
files.
CTFd
└── plugins
└── CTFd-plugin
├── README.md # README file
├── __init__.py # Main code file loaded by CTFd
├── requirements.txt # Any requirements that need to be installed
└── config.json # Plugin configuration file
Effectively CTFd will look at every folder in the CTFd/plugins folder for
the load() function.
If the load() function is found, CTFd will call that function with itself (as a
Flask app) as a parameter (i.e. load(app)). This is done after CTFd has
added all of its internal routes but before CTFd has fully instantiated itself.
This allows plugins to modify many aspects of CTFd without having to
modify CTFd itself.
config.json
{
"name": "CTFd Plugin",
"route": "/admin/custom_plugin_route"
}
This is ultimately rendered to the user with the following template snippet:
{% if plugins %}
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-haspopup="true" aria-expanded="false">Plugins <span
class="caret"></span></a>
<ul class="dropdown-menu">
{% for plugin in plugins %}
<li><a href="{{ request.script_root }}
{{ plugin.route }}">{{ plugin.name }}</a></li>
{% endfor %}
</ul>
</li>
{% endif %}
config.html
In the past CTFd used a static file known as config.html which existed to
give plugin developers a page that is loaded by the CTFd admin panel.
This has been superceded in favor of config.json but is still supported for
backwards compatability.
def load(app):
@app.route('/faq', methods=['GET'])
def view_faq():
return render_template('page.html', content="<h1>FAQ Page</h1>")
def load(app):
def view_challenges():
return render_template('page.html', content="<h1>Challenges are
currently closed</h1>")
If for some reason you wish to add a new method to an existing route you
can modify the url_map as follows:
app.url_map.add(Rule('/challenges', endpoint='challenges.challenges_view',
methods=['GET', 'POST']))
class Avatars(db.Model):
id = db.Column(db.Integer, primary_key=True)
team = db.Column(db.Integer, db.ForeignKey('teams.id'))
location = db.Column(db.Text)
def load(app):
app.db.create_all()
@app.route('/profile/avatar', methods=['GET', 'POST'])
def profile_avatars():
raise NotImplementedError
TIP
Replacing Templates
In some situations it might make sense for your plugin to replace the logic
for a single page template instead of creating an entire theme.
def load(app):
dir_path = Path(__file__).parent.resolve()
template_path = dir_path / 'templates' / 'new-scoreboard.html'
override_template('scoreboard.html', open(template_path).read())
def load(app):
# Available at http://ctfd/plugins/test_plugin/assets/
register_plugin_assets_directory(app,
base_path='/plugins/test_plugin/assets/')
def load(app):
# Available at http://ctfd/plugins/test_plugin/assets/file.js
register_plugin_asset(app,
asset_path='/plugins/test_plugin/assets/file.js')