Skip to content

Commit fe4ea56

Browse files
authored
Bootstrap beta 3, Regression fixes, bugfixes (CTFd#543)
* Upgrade to Bootstrap v4 beta 3 * Fix incorrect FontAwesome5 icon * Fixing regressions & code quality issues. Files, Tags & Hints now appear in the admin challenge preview. Fixed color issues with file buttons and badges. Pass script_root into challenge type plugin. * Fixing incorrect FontAwesome5 icon * Fix test for /admin/chals/<chalid> * Expand test to include tags, hints, files
1 parent d25a5d5 commit fe4ea56

17 files changed

+130
-65
lines changed

CTFd/admin/challenges.py

+31-11
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,31 @@ def admin_chal_types():
3131
@admins_only
3232
def admin_chals():
3333
if request.method == 'POST':
34-
chals = Challenges.query.add_columns('id', 'type', 'name', 'value', 'description', 'category', 'hidden', 'max_attempts').order_by(Challenges.value).all()
34+
chals = Challenges.query.order_by(Challenges.value).all()
3535

3636
json_data = {'game': []}
37-
for x in chals:
38-
type_class = CHALLENGE_CLASSES.get(x.type)
37+
for chal in chals:
38+
tags = [tag.tag for tag in Tags.query.add_columns('tag').filter_by(chal=chal.id).all()]
39+
files = [str(f.location) for f in Files.query.filter_by(chal=chal.id).all()]
40+
hints = []
41+
for hint in Hints.query.filter_by(chal=chal.id).all():
42+
hints.append({'id': hint.id, 'cost': hint.cost, 'hint': hint.hint})
43+
44+
type_class = CHALLENGE_CLASSES.get(chal.type)
3945
type_name = type_class.name if type_class else None
4046

4147
json_data['game'].append({
42-
'id': x.id,
43-
'name': x.name,
44-
'value': x.value,
45-
'description': x.description,
46-
'category': x.category,
47-
'hidden': x.hidden,
48-
'max_attempts': x.max_attempts,
49-
'type': x.type,
48+
'id': chal.id,
49+
'name': chal.name,
50+
'value': chal.value,
51+
'description': chal.description,
52+
'category': chal.category,
53+
'files': files,
54+
'tags': tags,
55+
'hints': hints,
56+
'hidden': chal.hidden,
57+
'max_attempts': chal.max_attempts,
58+
'type': chal.type,
5059
'type_name': type_name,
5160
'type_data': {
5261
'id': type_class.id,
@@ -77,6 +86,17 @@ def admin_chal_detail(chalid):
7786
return jsonify({'status': 0, 'message': message})
7887
elif request.method == 'GET':
7988
obj, data = chal_class.read(chal)
89+
90+
tags = [tag.tag for tag in Tags.query.add_columns('tag').filter_by(chal=chal.id).all()]
91+
files = [str(f.location) for f in Files.query.filter_by(chal=chal.id).all()]
92+
hints = []
93+
for hint in Hints.query.filter_by(chal=chal.id).all():
94+
hints.append({'id': hint.id, 'cost': hint.cost, 'hint': hint.hint})
95+
96+
data['tags'] = tags
97+
data['files'] = files
98+
data['hints'] = hints
99+
80100
return jsonify(data)
81101

82102

CTFd/plugins/challenges/assets/standard-challenge-modal.njk

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
<div class="row chal-files text-center pb-3">
5353
{% for file in files %}
5454
<div class='col-md-4 col-sm-4 col-xs-12 file-button-wrapper d-block'>
55-
<a class='btn btn-info btn-file mb-1 d-inline-block px-2 w-100 text-truncate' href='files/{{file}}'>
55+
<a class='btn btn-info btn-file mb-1 d-inline-block px-2 w-100 text-truncate' href='{{script_root}}/files/{{file}}'>
5656
<i class="fas fa-download"></i>
5757
<small>
5858
{{ file.split('/')[1] }}

CTFd/themes/admin/static/css/base.css

+5
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ pre {
106106

107107
.btn-info {
108108
background-color: #5B7290 !important;
109+
border-color: #5B7290 !important;
110+
}
111+
112+
.badge-info {
113+
background-color: #5B7290 !important;
109114
}
110115

111116
.alert {

CTFd/themes/admin/static/css/challenge-board.css

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
pre {
2+
margin: 0;
3+
padding: 0;
4+
}
5+
16
.chal-desc {
27
padding-left: 30px;
38
padding-right: 30px;
@@ -23,8 +28,4 @@
2328
background-color: #37d63e !important;
2429
opacity: 0.4;
2530
border: none;
26-
}
27-
28-
.key-submit .btn {
29-
height: 51px;
3031
}

CTFd/themes/admin/static/css/vendor/bootstrap.min.css

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CTFd/themes/admin/static/js/challenges/chalboard.js

+49-7
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,19 @@ function get_challenge(id){
2727

2828

2929
function load_challenge_preview(id){
30-
var chal = get_challenge(id);
31-
var modal_template = chal.type_data.templates.modal;
32-
var modal_script = chal.type_data.scripts.modal;
30+
loadchal(id, function(){
31+
var chal = get_challenge(id);
32+
var modal_template = chal.type_data.templates.modal;
33+
var modal_script = chal.type_data.scripts.modal;
3334

34-
render_challenge_preview(chal, modal_template, modal_script)
35+
render_challenge_preview(chal, modal_template, modal_script);
36+
});
3537
}
3638

3739
function render_challenge_preview(chal, modal_template, modal_script){
3840
var preview_window = $('#challenge-preview');
3941
$.get(script_root + modal_template, function (template_data) {
4042
preview_window.empty();
41-
console.log(chal.description);
4243
var template = nunjucks.compile(template_data);
4344
var data = {
4445
id: chal.id,
@@ -47,7 +48,8 @@ function render_challenge_preview(chal, modal_template, modal_script){
4748
tags: chal.tags,
4849
desc: chal.description,
4950
files: chal.files,
50-
hints: chal.hints
51+
hints: chal.hints,
52+
script_root: script_root
5153
};
5254

5355
var challenge = template.render(data);
@@ -61,14 +63,31 @@ function render_challenge_preview(chal, modal_template, modal_script){
6163
}
6264

6365

66+
function loadchal(chalid, cb){
67+
$.get(script_root + "/admin/chal/"+chalid, {
68+
}, function (data) {
69+
var categories = [];
70+
var challenge = $.parseJSON(JSON.stringify(data));
71+
72+
for (var i = challenges['game'].length - 1; i >= 0; i--) {
73+
if (challenges['game'][i]['id'] == challenge.id) {
74+
challenges['game'][i] = challenge
75+
}
76+
}
77+
78+
if (cb) {
79+
cb();
80+
}
81+
});
82+
}
83+
6484
function loadchals(cb){
6585
$.post(script_root + "/admin/chals", {
6686
'nonce': $('#nonce').val()
6787
}, function (data) {
6888
var categories = [];
6989
challenges = $.parseJSON(JSON.stringify(data));
7090

71-
7291
for (var i = challenges['game'].length - 1; i >= 0; i--) {
7392
if ($.inArray(challenges['game'][i].category, categories) == -1) {
7493
categories.push(challenges['game'][i].category)
@@ -90,6 +109,29 @@ loadchals(function(){
90109
});
91110
});
92111

112+
function loadhint(hintid) {
113+
ezq({
114+
title: "Unlock Hint?",
115+
body: "Are you sure you want to open this hint?",
116+
success: function () {
117+
$.post(script_root + "/hints/" + hintid, {'nonce': $('#nonce').val()}, function (data) {
118+
if (data.errors) {
119+
ezal({
120+
title: "Error!",
121+
body: data.errors,
122+
button: "Okay"
123+
});
124+
} else {
125+
ezal({
126+
title: "Hint",
127+
body: marked(data.hint, {'gfm': true, 'breaks': true}),
128+
button: "Got it!"
129+
});
130+
}
131+
});
132+
}
133+
});
134+
}
93135

94136
function submitkey(chal, key, nonce){
95137
$.post(script_root + "/admin/chal/" + chal, {

CTFd/themes/admin/static/js/files/files-utils.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
function updatefiles(){
2-
chal = $('#files-chal').val();
2+
var chal = $('#files-chal').val();
33
var form = $('#update-files form')[0];
44
var formData = new FormData(form);
55
$.ajax({
@@ -20,12 +20,12 @@ function loadfiles(chal, cb){
2020
$('#update-files form').attr('action', script_root+'/admin/files/'+chal)
2121
$.get(script_root + '/admin/files/' + chal, function(data){
2222
$('#files-chal').val(chal);
23-
files = $.parseJSON(JSON.stringify(data));
24-
files = files['files'];
23+
var files = $.parseJSON(JSON.stringify(data));
24+
var files = files['files'];
2525
$('#current-files').empty();
26-
for(x=0; x<files.length; x++){
27-
filename = files[x].file.split('/');
28-
filename = filename[filename.length - 1];
26+
for(var x = 0; x < files.length; x++){
27+
var filename = files[x].file.split('/');
28+
var filename = filename[filename.length - 1];
2929

3030
var curr_file = '<div class="col-md-12"><a href="{2}/files/{3}">{4}</a> <i class="btn-fa fas fa-times float-right" onclick="deletefile({0}, {1}, $(this))" value="{2}" ></i></div>'.format(
3131
chal,

CTFd/themes/admin/static/js/vendor/bootstrap.bundle.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CTFd/themes/admin/templates/challenges.html

+5-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
{% extends "admin/base.html" %}
22

33
{% block stylesheets %}
4-
<style>
5-
pre {
6-
margin: 0;
7-
padding: 0;
8-
}
9-
</style>
4+
<link rel="stylesheet" href="{{ request.script_root }}/themes/admin/static/css/challenge-board.css">
105
{% endblock %}
116

127

@@ -97,13 +92,13 @@ <h1>Challenges
9792
<span>&nbsp; &nbsp;</span>
9893

9994
<i class="btn-fa fas fa-flag edit-keys" aria-hidden="true" data-toggle="tooltip" data-placement="top"
100-
title="Edit Flags" chal-id="{{ challenge.id }}"></i>
95+
title="Edit {{ challenge.name }} flags" chal-id="{{ challenge.id }}"></i>
10196
<i class="btn-fa fas fa-download edit-files" aria-hidden="true" data-toggle="tooltip"
102-
data-placement="top" title="Edit Files" chal-id="{{ challenge.id }}"></i>
97+
data-placement="top" title="Edit {{ challenge.name }} files" chal-id="{{ challenge.id }}"></i>
10398
<i class="btn-fa fas fa-tags edit-tags" aria-hidden="true" data-toggle="tooltip" data-placement="top"
104-
title="Edit Tags" chal-id="{{ challenge.id }}"></i>
99+
title="Edit {{ challenge.name }} tags" chal-id="{{ challenge.id }}"></i>
105100
<i class="btn-fa fas fa-question-circle edit-hints" aria-hidden="true" data-toggle="tooltip"
106-
data-placement="top" title="Edit Hints" chal-id="{{ challenge.id }}"></i>
101+
data-placement="top" title="Edit {{ challenge.name }} hints" chal-id="{{ challenge.id }}"></i>
107102

108103
<span>&nbsp; &nbsp;</span>
109104

CTFd/themes/admin/templates/editor.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ <h3>Content</h3>
225225
'svg': 'fa-file-image',
226226

227227
// Text Files
228-
'txt': 'fa-file-text',
228+
'txt': 'fa-file-alt',
229229

230230
// Video Files
231231
'mov': 'fa-file-video',
@@ -270,7 +270,7 @@ <h3>Content</h3>
270270
link.attr('href', '##');
271271

272272
if (mapping[ext] == undefined)
273-
link.append('<i class="far fa-file-o" aria-hidden="true"></i> '.format(mapping[ext]));
273+
link.append('<i class="far fa-file" aria-hidden="true"></i> '.format(mapping[ext]));
274274
else
275275
link.append('<i class="far {0}" aria-hidden="true"></i> '.format(mapping[ext]));
276276

CTFd/themes/core/static/css/base.css

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ table > thead > tr > td {
105105
border-color: #5B7290 !important;
106106
}
107107

108+
.badge-info {
109+
background-color: #5B7290 !important;
110+
}
111+
108112
.alert {
109113
border-radius: 0 !important;
110114
padding: 0.8em;

CTFd/themes/core/static/css/challenge-board.css

-10
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@
1919
background-color: #5B7290 !important;
2020
}
2121

22-
.btn-file:nth-child(1):before {
23-
/*content: "\f0ed";*/
24-
/*display: inline-block;*/
25-
/*font: normal normal normal 14px/1 FontAwesome;*/
26-
/*font-size: inherit;*/
27-
/*text-rendering: auto;*/
28-
/*-webkit-font-smoothing: antialiased;*/
29-
/*-moz-osx-font-smoothing: grayscale;*/
30-
}
31-
3222
.challenge-button {
3323
box-shadow: 3px 3px 3px grey;
3424
}

CTFd/themes/core/static/css/vendor/bootstrap.min.css

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CTFd/themes/core/static/js/chalboard.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ function loadchalbyname(chalname) {
2121
function updateChalWindow(obj) {
2222
$.get(script_root + obj.template, function(template_data){
2323
$('#chal-window').empty();
24-
templates[obj.type] = template_data;
25-
var template_data = templates[obj.type];
26-
template_data['script_root'] = script_root;
2724
var template = nunjucks.compile(template_data);
2825
var solves = obj.solves == 1 ? " Solve" : " Solves";
2926
var solves = obj.solves + solves;
@@ -37,7 +34,8 @@ function updateChalWindow(obj) {
3734
desc: obj.description,
3835
solves: solves,
3936
files: obj.files,
40-
hints: obj.hints
37+
hints: obj.hints,
38+
script_root: script_root
4139
};
4240

4341
$('#chal-window').append(template.render(wrapper));

CTFd/themes/core/static/js/vendor/bootstrap.bundle.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/admin/test_admin_facing.py

+7
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,20 @@ def test_admin_chal_detail_returns_proper_data():
209209
client = login_as_user(app, name="admin", password="password")
210210

211211
chal = gen_challenge(app.db)
212+
tag = gen_tag(app.db, chal.id, 'test-tag')
213+
hint = gen_hint(app.db, chal.id, 'test-hint', 5)
214+
f = gen_file(app.db, chal.id, '0bf1a55a5cd327c07af15df260979668/bird.swf')
215+
212216
chal_class = get_chal_class(chal.type)
213217
data = {
214218
'id': chal.id,
215219
'name': chal.name,
216220
'value': chal.value,
217221
'description': chal.description,
218222
'category': chal.category,
223+
'files': ['0bf1a55a5cd327c07af15df260979668/bird.swf'],
224+
'tags': ['test-tag'],
225+
'hints': [{'id': 1, 'cost': 5, 'hint': 'test-hint'}],
219226
'hidden': chal.hidden,
220227
'max_attempts': chal.max_attempts,
221228
'type': chal.type,

tests/helpers.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,11 @@ def gen_tag(db, chal, tag='tag_tag'):
110110
return tag
111111

112112

113-
def gen_file():
114-
pass
113+
def gen_file(db, chal, location):
114+
f = Files(chal, location)
115+
db.session.add(f)
116+
db.session.commit()
117+
return f
115118

116119

117120
def gen_flag(db, chal, flag='flag', key_type='static'):

0 commit comments

Comments
 (0)