Skip to content

Commit

Permalink
feat: modify to dynamic chanls
Browse files Browse the repository at this point in the history
  • Loading branch information
XuCcc committed Feb 20, 2018
1 parent 016b5a0 commit 7928c23
Show file tree
Hide file tree
Showing 13 changed files with 485 additions and 12 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@

## Reference

* https://github.com/CTFd/CTFd/wiki/Plugins
* https://github.com/CTFd/CTFd/wiki/Plugins
* https://mozilla.github.io/nunjucks/cn/templating.html#part-9d9c663eba1f6097
65 changes: 65 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,77 @@
from flask import request, jsonify

from CTFd.plugins import register_plugin_assets_directory
from CTFd.plugins.challenges import BaseChallenge, CHALLENGE_CLASSES
from CTFd.models import db, Solves, WrongKeys, Keys, Challenges, Files, Tags, Teams
from CTFd.plugins.keys import BaseKey,KEY_CLASSES
from CTFd.models import db, Keys
from CTFd.utils import admins_only, is_admin

dynamic = Blueprint('dynamic', __name__)

class Online(object):
def __init__(self, ):
"""Constructor for Online"""
super(Online, self).__init__()




class OnlineTypeChallenge(BaseChallenge):
id = 'online'
name = 'online'
templates = { # Handlebars templates used for each aspect of challenge editing & viewing
'create': '/plugins/DynamicFlag/assets/online-challenge-create.njk',
'update': '/plugins/DynamicFlag/assets/online-challenge-update.njk',
'modal': '/plugins/DynamicFlag/assets/online-challenge-modal.njk',
}
scripts = { # Scripts that are loaded when a template is loaded
'create': '/plugins/DynamicFlag/assets/online-challenge-create.js',
'update': '/plugins/DynamicFlag/assets/online-challenge-update.js',
'modal': '/plugins/DynamicFlag/assets/online-challenge-modal.js',
}

@staticmethod
def create(request):
"""
This method is used to process the challenge creation request.
:param request:
:return:
"""
# Create challenge
chal = Challenges(
name=request.form['name'],
description=request.form['description'],
value=request.form['value'],
category=request.form['category'],
type=request.form['chaltype']
)

if 'hidden' in request.form:
chal.hidden = True
else:
chal.hidden = False

max_attempts = request.form.get('max_attempts')
if max_attempts and max_attempts.isdigit():
chal.max_attempts = int(max_attempts)

db.session.add(chal)
db.session.commit()

flag = Keys(chal.id, request.form['key'], request.form['key_type[0]'])
if request.form.get('keydata'):
flag.data = request.form.get('keydata')
db.session.add(flag)

db.session.commit()

files = request.files.getlist('files[]')
for f in files:
utils.upload_file(file=f, chalid=chal.id)

db.session.commit()

class DynamicKey(BaseKey):
id = 2
Expand Down
2 changes: 2 additions & 0 deletions assets/create-dynamic-modal.njk
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
<label for="create-key-static" class="control-label">Enter Dynamic Key Token</label>
<input type="text" id="create-key-dynamic" class="form-control" name="key" value="{{key}}" placeholder="Enter dynamic key data">
<input type="text" id="create-key-dynamic" class="form-control" name="keydata" value="{{keydata}}" placeholder="Enter dynamic key token">

2 changes: 1 addition & 1 deletion assets/edit-dynamic-modal.njk
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</div>
<div class="modal-body">
<form method="POST" action="{{ script_root }}/admin/keys/{{id}}">
<input type="text" id="key-data" class="form-control" name="keydata" value="{{keydata}}" placeholder="Enter dynamic key token">
<input type="text" id="key-data" class="form-control" name="keydata" value="{{key}}" placeholder="Enter dynamic key token">
<input type="hidden" id="key-type" name="key_type" value="dynamic">
<input type="hidden" id="key-id">
<hr>
Expand Down
23 changes: 23 additions & 0 deletions assets/online-challenge-create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Markdown Preview
$('#desc-edit').on('shown.bs.tab', function (event) {
if (event.target.hash == '#desc-preview'){
$(event.target.hash).html(marked($('#desc-editor').val(), {'gfm':true, 'breaks':true}));
}
});
$('#new-desc-edit').on('shown.bs.tab', function (event) {
if (event.target.hash == '#new-desc-preview'){
$(event.target.hash).html(marked($('#new-desc-editor').val(), {'gfm':true, 'breaks':true}));
}
});
$("#solve-attempts-checkbox").change(function() {
if(this.checked) {
$('#solve-attempts-input').show();
} else {
$('#solve-attempts-input').hide();
$('#max_attempts').val('');
}
});

$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
99 changes: 99 additions & 0 deletions assets/online-challenge-create.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<form method="POST" action="{{ script_root }}/admin/chal/new" enctype="multipart/form-data">
<div class="form-group">
<label for="name">Name
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="The name of your challenge"></i>
</label>
<input type="text" class="form-control" name="name" placeholder="Enter challenge name">
</div>
<div class="form-group">
<label for="category">Category
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="The category of your challenge"></i>
</label>
<input type="text" class="form-control" name="category" placeholder="Enter challenge category">
</div>

<ul class="nav nav-tabs" role="tablist" id="new-desc-edit">
<li class="nav-item">
<a class="nav-link active" href="#new-desc-write" aria-controls="home" role="tab" data-toggle="tab">Write</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#new-desc-preview" aria-controls="home" role="tab" data-toggle="tab">Preview</a>
</li>
</ul>

<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="new-desc-write">
<div class="form-group">
<label for="message-text" class="control-label">Message:
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="Use this to give a brief introduction to your challenge. The description supports HTML and Markdown."></i>
</label>
<textarea id="new-desc-editor" class="form-control" name="description" rows="10"></textarea>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="new-desc-preview" style="height:234px; overflow-y: scroll;">
</div>
</div>

<div class="form-group">
<label for="value">Value
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="This is how many points are rewarded for solving this challenge."></i>
</label>
<input type="number" class="form-control" name="value" placeholder="Enter value" required>
</div>

<div class="form-group">
<label>Flag
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="This is the flag or solution for your challenge. You can choose whether your flag is a static string or a regular expression."></i>
</label>
<input type="text" class="form-control" name="key" placeholder="Enter flag">
</div>

<div class="form-group">
<select class="custom-select" name="key_type[0]">
<option value="static">Static</option>
<option value="regex">Regex</option>
</select>
</div>

<div class="form-check">
<div class="checkbox">
<label class="form-check-label">
<input class="form-check-input" name="hidden" type="checkbox">
Hide challenge on creation
</label>
</div>
</div>

<div class="form-check">
<div class="checkbox">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" id="solve-attempts-checkbox">
Limit amount of solve attempts
</label>
</div>
</div>

<div class="form-group">
<div id="solve-attempts-input" style="display: none;">
<label for="max_attempts">Maximum Attempts
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="How many attempts should a user have for this challenge? For unlimited attempts, use the value 0"></i>
</label>
<input class="form-control" id='max_attempts' name='max_attempts' type='number' placeholder="0">
</div>
</div>

<div class="form-group">
<label>Upload Challenge Files
<i class="far fa-question-circle text-muted cursor-help" data-toggle="tooltip" data-placement="right" title="Challenges files are provided to users for download alongside your challenge description"></i>
</label>
<input class="form-control-file" type="file" name="files[]" multiple="multiple">
<sub class="help-block">Attach multiple files using Control+Click or Cmd+Click.</sub>
</div>

<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
<input type="hidden" value="standard" name="chaltype" id="chaltype">

<div class="form-group">
<button class="btn btn-primary float-right create-challenge-submit" type="submit">Create</button>
</div>
</form>
29 changes: 29 additions & 0 deletions assets/online-challenge-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
$('#submit-key').unbind('click');
$('#submit-key').click(function (e) {
e.preventDefault();
submitkey($('#chal-id').val(), $('#answer-input').val(), $('#nonce').val())
});

$("#answer-input").keyup(function(event){
if(event.keyCode == 13){
$("#submit-key").click();
}
});

$(".input-field").bind({
focus: function() {
$(this).parent().addClass('input--filled' );
$label = $(this).siblings(".input-label");
},
blur: function() {
if ($(this).val() === '') {
$(this).parent().removeClass('input--filled' );
$label = $(this).siblings(".input-label");
$label.removeClass('input--hide' );
}
}
});
var content = $('.chal-desc').text();
var decoded = $('<textarea/>').html(content).val()

$('.chal-desc').html(marked(content, {'gfm':true, 'breaks':true}));
104 changes: 104 additions & 0 deletions assets/online-challenge-modal.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" href="#challenge">Challenge</a>
</li>
{% if solves == '-1 Solves' %}
{% else %}
<li class="nav-item">
<a class="nav-link chal-solves" href="#solves">{{solves}}</a>
</li>
{% endif %}
</ul>
<div role="tabpanel">
<div class="tab-content">
<div role="tabpanel" class="tab-pane fade show active" id="challenge">
<h2 class='chal-name text-center pt-3'>{{ name }}</h2>
<h3 class="chal-value text-center">{{ value }}</h3>
<div class="chal-tags text-center">
{% for tag in tags %}
<span class='badge badge-info chal-tag'>{{tag}}</span>
{% endfor %}
</div>
<span class="chal-desc">{{ desc }}</span>
<div class="chal-hints hint-row row">
{% for hint in hints %}
<div class='col-md-12 hint-button-wrapper text-center mb-3'>
<a class="btn btn-info btn-hint btn-block" href="javascript:;" onclick="javascript:loadhint({{hint.id}})">
{% if hint.hint %}
<small>
View Hint
</small>
{% else %}
{% if hint.cost %}
<small>
Unlock Hint for {{hint.cost}} points
</small>
{% else %}
<small>
View Hint
</small>
{% endif %}
{% endif %}
</a>
</div>
{% endfor %}
</div>
<div class="row chal-files text-center pb-3">
{% for file in files %}
<div class='col-md-4 col-sm-4 col-xs-12 file-button-wrapper d-block'>
<a class='btn btn-info btn-file mb-1 d-inline-block px-2 w-100 text-truncate' href='{{script_root}}/files/{{file}}'>
<i class="fas fa-download"></i>
<small>
{{ file.split('/')[1] }}
</small>
</a>
</div>
{% endfor %}
</div>

<div class="row submit-row">
<div class="col-md-9 form-group">
<input class="form-control" type="text" name="answer" id="answer-input" placeholder="Flag" />
<input id="chal-id" type="hidden" value="{{id}}">
</div>
<div class="col-md-3 form-group key-submit">
<button type="submit" id="submit-key" tabindex="5" class="btn btn-md btn-outline-secondary float-right">Submit</button>
</div>
</div>
<div class="row notification-row">
<div class="col-md-12">
<div id="result-notification" class="alert alert-dismissable text-center w-100" role="alert" style="display: none;">
<strong id="result-message"></strong>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane fade" id="solves">
<div class="row">
<div class="col-md-12">
<table class="table table-striped text-center">
<thead>
<tr>
<td><b>Name</b>
</td>
<td><b>Date</b>
</td>
</tr>
</thead>
<tbody id="chal-solves-names">
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Loading

0 comments on commit 7928c23

Please sign in to comment.