Skip to content
This repository was archived by the owner on May 11, 2025. It is now read-only.

Commit 04b0815

Browse files
committed
first commit
0 parents  commit 04b0815

16 files changed

+507
-0
lines changed

.github/workflows/main.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Format Python Code
2+
on:
3+
push:
4+
branches:
5+
- '**'
6+
jobs:
7+
python-code-format:
8+
runs-on: ubuntu-20.04
9+
steps:
10+
- uses: actions/checkout@v2
11+
- uses: actions/setup-python@v4
12+
with:
13+
python-version: "3.10"
14+
architecture: "x64"
15+
- name: Display Python version
16+
run: python --version
17+
- name: Install packages
18+
run: pip install black autopep8 isort
19+
- name: Formatter
20+
run: |
21+
black .
22+
autopep8 --recursive --in-place --aggressive --aggressive .
23+
isort .
24+
- name: Create Pull Request
25+
uses: peter-evans/create-pull-request@v3
26+
with:
27+
commit-message: Auto code format
28+
title: Fixes by format action
29+
body: This is an auto-generated PR with fixes.
30+
labels: automated pr
31+
branch: python-code-format-patches

.github/workflows/pylint.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Pylint
2+
3+
on: [push]
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
python-version: ["3.8", "3.9", "3.10"]
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up Python ${{ matrix.python-version }}
15+
uses: actions/setup-python@v3
16+
with:
17+
python-version: ${{ matrix.python-version }}
18+
19+
- name: Install dependencies
20+
run: |
21+
python -m pip install --upgrade pip
22+
pip install pylint
23+
24+
- name: Analysing the code with pylint
25+
run: |
26+
git ls-files '**/*.py' | xargs pylint || echo "No Python files to lint."

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
!.venv/pyvenv.cfg
2+
3+
.venv
4+
**/*.pyc
5+
**/__pycache__

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"pylint.path": [
3+
"\"D:\\NewComp\\DevProjects\\JCT\\Networking\\comms2_ctf\\flask_server\\.venv\\Lib\\site-packages\""
4+
]
5+
}

hints/__init__.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from flask import Flask
2+
# from ctf.error_handlers import register_error_handlers # Adjust the import based on your project structure
3+
4+
def create_app():
5+
app = Flask(
6+
__name__,
7+
static_folder="static",
8+
static_url_path="/",
9+
template_folder="templates",
10+
)
11+
app.config["SECRET_KEY"] = "CTF_K3YF0RS355i0n5!"
12+
# ensure session cookie is httponly
13+
app.config["SESSION_COOKIE_HTTPONLY"] = True
14+
# ensure session cookie is same site
15+
app.config["SESSION_COOKIE_SAMESITE"] = "Strict"
16+
app.config["REMEMBER_COOKIE_SECURE"] = True # ensure remember cookie is secure
17+
app.config["SESSION_COOKIE_SECURE"] = True # ensure session cookie is secure
18+
19+
with app.app_context():
20+
from . import routes
21+
app.register_blueprint(routes.bp)
22+
# register_error_handlers(app)
23+
# app.config['referrer_policy'] = 'strict-origin-when-cross-origin'
24+
return app
25+
# app = Flask(
26+
# __name__,
27+
# static_folder="static",
28+
# static_url_path="/",
29+
# template_folder="templates",
30+
# )
31+
32+
33+
# register_error_handlers(app)
34+
# app.config['referrer_policy'] = 'strict-origin-when-cross-origin'
35+
36+
from hints import routes

hints/routes.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from flask import Blueprint, render_template, request, redirect, url_for, flash, make_response, session
2+
import datetime
3+
4+
bp = Blueprint('ctf', __name__)
5+
6+
# Sample dictionary with flags and multiple hints
7+
stages = {
8+
1: {
9+
"flag": "flag{stage1}",
10+
"hints": [
11+
"This is the least revealing hint for stage 1.",
12+
"This is a more revealing hint for stage 1.",
13+
"This is the most revealing hint for stage 1."
14+
]
15+
},
16+
2: {
17+
"flag": "flag{stage2}",
18+
"hints": [
19+
"This is the least revealing hint for stage 2.",
20+
"This is a more revealing hint for stage 2.",
21+
"This is the most revealing hint for stage 2."
22+
]
23+
},
24+
3: {
25+
"flag": "flag{stage3}",
26+
"hints": [
27+
"Almost there"
28+
]
29+
}
30+
}
31+
32+
current_stage = 1
33+
hint_index = 0
34+
35+
@bp.route('/flags', methods=['GET', 'POST'])
36+
@bp.route('/flags.html', methods=['GET', 'POST'])
37+
def flags():
38+
global current_stage, hint_index
39+
# initialize session variables
40+
if "submitted_flags" not in session:
41+
session['submitted_flags'] = []
42+
if "current_stage" not in session:
43+
session['current_stage'] = 1
44+
45+
current_stage = session['current_stage']
46+
submitted_flags = session['submitted_flags']
47+
# need to verify that the user didn't try to skip stages or trick the system
48+
49+
if request.method == 'POST':
50+
if 'submit_flag' in request.form:
51+
submitted_flag = request.form.get('flag')
52+
if submitted_flag == stages[current_stage]['flag']:
53+
flash(f"Correct flag for Stage {current_stage}!", 'success')
54+
submitted_flags.append(submitted_flag)
55+
session['submitted_flags'] = submitted_flags
56+
if current_stage < len(stages):
57+
current_stage += 1
58+
hint_index = 0
59+
elif current_stage == len(stages):
60+
flash("You have completed all the stages. Congratulations!", 'success')
61+
# if the user has completed all the stages, then flash a message
62+
session['current_stage'] = current_stage
63+
else:
64+
found = False
65+
# if the flag is for a different stage, then put them on their stage
66+
for stage, stage_data in stages.items():
67+
if submitted_flag == stage_data['flag']:
68+
flash(f"That's the flag for stage {stage}, but in the wrong order", 'info')
69+
current_stage = stage
70+
hint_index = 0
71+
found = True
72+
break
73+
# else:
74+
if not found:
75+
flash("Incorrect flag. Try again.", 'danger')
76+
77+
elif 'reveal_hint' in request.form:
78+
if hint_index < len(stages[current_stage]['hints']) - 1: # if there are more hints to reveal
79+
hint_index += 1
80+
else:
81+
# if the user exhausted all the hints, have it show from the beginning
82+
hint_index = 0
83+
# flash a message to the user
84+
85+
flash("No new hints :( Try harder!", 'info')
86+
87+
hints = stages[current_stage]['hints'][:hint_index + 1]
88+
return render_template('flags.html', stage=current_stage, hints=hints, hint_index=hint_index, submitted_flags=submitted_flags)
89+
90+
91+
@bp.route('/', methods=['GET', 'POST']) # also for index
92+
@bp.route('/index', methods=['GET', 'POST'])
93+
@bp.route('/home', methods=['GET', 'POST'])
94+
@bp.route('/index.html', methods=['GET', 'POST'])
95+
def index():
96+
# initialize session variables
97+
if "submitted_flags" not in session:
98+
session['submitted_flags'] = []
99+
if "current_stage" not in session:
100+
session['current_stage'] = 1
101+
102+
flash("Welcome to the CTF! Can you find the flags?", 'info')
103+
brief = """
104+
Do not use this site for any illegal activities, please do not attack it in any way as it harms other users who are solving the CTF.
105+
This site is not a part of the CTF challenge itself, but a tool to help you keep track of your progress. The flags are not hidden on this site. You need to find them on your own. Good luck!
106+
"""
107+
108+
return render_template('index.html', summary= brief)
109+
110+
@bp.route('/restart')
111+
@bp.route('/reset')
112+
def restart():
113+
session.clear()
114+
flash("Progress reset. You are back to Stage 1.", 'info')
115+
# reroute to index
116+
return redirect(url_for('ctf.index'))
117+
# resp = make_response(redirect(url_for('ctf.index')))
118+
# resp.set_cookie('stage', '1', httponly=True)
119+
# resp.set_cookie('hint_index', '0', httponly=True)
120+
# flash("Progress reset. You are back to Stage 1.", 'info')
121+
# return resp
122+
123+
124+
125+
@bp.context_processor
126+
def inject_today_date():
127+
"""
128+
used for the footer to display the current year
129+
"""
130+
return {'year': datetime.date.today().year}

hints/static/css/style.css

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
body {
2+
font-family: 'Arial', sans-serif;
3+
margin: 0;
4+
padding: 0;
5+
}
6+
7+
.container {
8+
width: 80%;
9+
margin: 0 auto;
10+
}
11+
12+
/* change color */
13+
.important {
14+
color: #336699;
15+
}
16+
17+
.error {
18+
color: red;
19+
}
20+
21+
/* .alert {
22+
padding: 20px;
23+
background-color: #f44336;
24+
color: white;
25+
margin-bottom: 15px;
26+
} */
27+
28+
.main-content {
29+
display: flex;
30+
}
31+
.main-section {
32+
flex: 1;
33+
}
34+
.sidebar {
35+
width: 250px;
36+
margin-left: 20px;
37+
}

hints/static/robots.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
User-agent: *
2+
# only allow the index page
3+
Allow: /index.html
4+
Disallow: /
5+

hints/templates/404.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{% extends "layout.html" %}
2+
3+
{#<!-- Exports header and navbar from header.html or any file you want-->#}
4+
5+
{% block title %}Page Not Found{% endblock %}
6+
7+
{% block head %}
8+
{{ super() }}
9+
10+
{% endblock %}
11+
12+
{% block content %}
13+
<h1 class="error">
14+
{{ "404 Page Not Found" }}
15+
</h1>
16+
17+
{% block body %}
18+
<h2>Oops! Looks like the page doesn't exist anymore</h2>
19+
<a href="{{ url_for('index') }}">Click Here</a> to go to the Home Page
20+
21+
{% endblock %}
22+
23+
{% endblock %}

hints/templates/flags.html

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{% extends "layout.html" %}
2+
3+
{#<!-- Exports header and navbar from header.html -->#}
4+
{% block title %}{{ title }}{% endblock %}
5+
6+
{% block head %}
7+
{{ super() }}
8+
9+
{% endblock %}
10+
{% block content %}
11+
<div class="container mt-5">
12+
<h1 class="text-center">CTF Platform</h1>
13+
<div class="mt-4">
14+
<h3>Stage {{ stage }}</h3>
15+
<form method="POST">
16+
<div class="form-group">
17+
<label for="flag">Enter Flag:</label>
18+
<input type="text" id="flag" name="flag" class="form-control" placeholder="flag{...}">
19+
</div>
20+
<button type="submit" name="submit_flag" class="btn btn-primary">Submit Flag</button>
21+
</form>
22+
</div>
23+
{% with messages = get_flashed_messages(with_categories=true) %}
24+
{% if messages %}
25+
<div class="mt-4">
26+
{% for category, message in messages %}
27+
<div class="alert alert-{{ category }}" >{{ message }}</div>
28+
{% endfor %}
29+
</div>
30+
{% endif %}
31+
{% endwith %}
32+
<div class="mt-4">
33+
<h4>Hints:</h4>
34+
{% if hints %}
35+
<ul>
36+
{% for hint in hints %}
37+
<li>{{ hint }}</li>
38+
{% endfor %}
39+
</ul>
40+
{% else %}
41+
<p>No hints revealed yet.</p>
42+
{% endif %}
43+
<form method="POST">
44+
<button type="submit" name="reveal_hint" class="btn btn-secondary">Reveal Next Hint</button>
45+
</form>
46+
{#<!-- {% if hint_index < len(stages[stage]['hints']) - 1 %} -->
47+
<form method="POST">
48+
<button type="submit" name="reveal_hint" class="btn btn-secondary">Reveal Next Hint</button>
49+
</form>
50+
<!-- {% endif %} -->#}
51+
</div>
52+
<div class="mt-4">
53+
<a href="{{ url_for('ctf.restart') }}" class="btn btn-danger">Restart Challenge</a>
54+
</div>
55+
<div class="sidebar">
56+
<h4>Previously Entered Flags</h4>
57+
{% if submitted_flags %}
58+
<ul>
59+
{% for flag in submitted_flags %}
60+
<li>{{ flag }}</li>
61+
{% endfor %}
62+
</ul>
63+
{% else %}
64+
<p>No flags entered yet.</p>
65+
{% endif %}
66+
</div>
67+
68+
</div>
69+
{% endblock %}
70+

0 commit comments

Comments
 (0)