diff --git a/.gitignore b/.gitignore
index 54707f74..ce8bcb3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,4 @@ CTFd/static/uploads
CTFd/uploads
.data/
.ctfd_secret_key
+.*.swp
diff --git a/CTFd/admin/challenges.py b/CTFd/admin/challenges.py
index 8b733bcd..562bfaba 100644
--- a/CTFd/admin/challenges.py
+++ b/CTFd/admin/challenges.py
@@ -25,7 +25,7 @@ def admin_chal_types():
@admins_only
def admin_chals():
if request.method == 'POST':
- chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category', 'hidden', 'max_attempts').order_by(Challenges.value).all()
+ chals = Challenges.query.add_columns('id', 'type', 'name', 'value', 'description', 'category', 'hidden', 'max_attempts').order_by(Challenges.value).all()
teams_with_points = db.session.query(Solves.teamid).join(Teams).filter(
Teams.banned == False).group_by(Solves.teamid).count()
@@ -39,6 +39,9 @@ def admin_chals():
else:
percentage = 0.0
+ type_class = CHALLENGE_CLASSES.get(x.type)
+ type_name = type_class.name if type_class else None
+
json_data['game'].append({
'id': x.id,
'name': x.name,
@@ -47,6 +50,8 @@ def admin_chals():
'category': x.category,
'hidden': x.hidden,
'max_attempts': x.max_attempts,
+ 'type': x.type,
+ 'type_name': type_name,
'percentage_solved': percentage
})
@@ -286,4 +291,4 @@ def admin_update_chal():
db.session.add(challenge)
db.session.commit()
db.session.close()
- return redirect(url_for('admin_challenges.admin_chals'))
\ No newline at end of file
+ return redirect(url_for('admin_challenges.admin_chals'))
diff --git a/CTFd/static/admin/js/chal-new.js b/CTFd/static/admin/js/chal-new.js
new file mode 100644
index 00000000..b56b1bf1
--- /dev/null
+++ b/CTFd/static/admin/js/chal-new.js
@@ -0,0 +1,33 @@
+function load_chal_template(chal_type_name){
+ $.get(script_root + '/static/admin/js/templates/challenges/'+ chal_type_name +'/' + chal_type_name + '-challenge-create.hbs', function(template_data){
+ var template = Handlebars.compile(template_data);
+ $("#create-chal-entry-div").html(template({'nonce':nonce, 'script_root':script_root}));
+ $.getScript(script_root + '/static/admin/js/templates/challenges/'+chal_type_name+'/'+chal_type_name+'-challenge-create.js', function(){
+ console.log('loaded');
+ });
+ });
+}
+
+
+nonce = "{{ nonce }}";
+$.get(script_root + '/admin/chal_types', function(data){
+ console.log(data);
+ $("#create-chals-select").empty();
+ var chal_type_amt = Object.keys(data).length;
+ if (chal_type_amt > 1){
+ var option = "";
+ $("#create-chals-select").append(option);
+ for (var key in data){
+ var option = "".format(key, data[key]);
+ $("#create-chals-select").append(option);
+ }
+ } else if (chal_type_amt == 1) {
+ var key = Object.keys(data)[0];
+ $("#create-chals-select").parent().parent().parent().empty();
+ load_chal_template(data[key]);
+ }
+});
+$('#create-chals-select').change(function(){
+ var chal_type_name = $(this).find("option:selected").text();
+ load_chal_template(chal_type_name);
+});
diff --git a/CTFd/static/admin/js/chalboard.js b/CTFd/static/admin/js/chalboard.js
index 8a4c5f5b..71deb52d 100644
--- a/CTFd/static/admin/js/chalboard.js
+++ b/CTFd/static/admin/js/chalboard.js
@@ -38,255 +38,25 @@ function load_edit_key_modal(key_id, key_type_name) {
});
}
-function load_hint_modal(method, hintid){
- $('#hint-modal-hint').val('');
- $('#hint-modal-cost').val('');
- if (method == 'create'){
- $('#hint-modal-submit').attr('action', '/admin/hints');
- $('#hint-modal-title').text('Create Hint');
- $("#hint-modal").modal();
- } else if (method == 'update'){
- $.get(script_root + '/admin/hints/' + hintid, function(data){
- $('#hint-modal-submit').attr('action', '/admin/hints/' + hintid);
- $('#hint-modal-hint').val(data.hint);
- $('#hint-modal-cost').val(data.cost);
- $('#hint-modal-title').text('Update Hint');
- $("#hint-modal-button").text('Update Hint');
- $("#hint-modal").modal();
- });
- }
-}
-
-function loadchal(id, update) {
- // $('#chal *').show()
- // $('#chal > h1').hide()
+function load_chal_template(id, success_cb){
obj = $.grep(challenges['game'], function (e) {
return e.id == id;
})[0]
- $('#desc-write-link').click() // Switch to Write tab
- $('.chal-title').text(obj.name);
- $('.chal-name').val(obj.name);
- $('.chal-desc').val(obj.description);
- $('.chal-value').val(obj.value);
- if (parseInt(obj.max_attempts) > 0){
- $('.chal-attempts').val(obj.max_attempts);
- $('#limit_max_attempts').prop('checked', true);
- $('#chal-attempts-group').show();
- }
- $('.chal-category').val(obj.category);
- $('.chal-id').val(obj.id);
- $('.chal-hidden').prop('checked', false);
- if (obj.hidden) {
- $('.chal-hidden').prop('checked', true);
- }
- //$('#update-challenge .chal-delete').attr({
- // 'href': '/admin/chal/close/' + (id + 1)
- //})
- if (typeof update === 'undefined')
- $('#update-challenge').modal();
-}
-
-function submitkey(chal, key) {
- $.post(script_root + "/admin/chal/" + chal, {
- key: key,
- nonce: $('#nonce').val()
- }, function (data) {
- alert(data)
- })
-}
-
-function create_key(chal, key, key_type) {
- $.post(script_root + "/admin/keys", {
- chal: chal,
- key: key,
- key_type: key_type,
- nonce: $('#nonce').val()
- }, function (data) {
- if (data == "1"){
- loadkeys(chal);
- $("#create-keys").modal('toggle');
- }
- });
-}
-
-function loadkeys(chal){
- $.get(script_root + '/admin/chal/' + chal + '/keys', function(data){
- $('#keys-chal').val(chal);
- keys = $.parseJSON(JSON.stringify(data));
- keys = keys['keys'];
- $('#current-keys').empty();
- $.get(script_root + "/static/admin/js/templates/admin-keys-table.hbs", function(data){
- var template = Handlebars.compile(data);
- var wrapper = {keys: keys, script_root: script_root};
- $('#current-keys').append(template(wrapper));
+ $.get(script_root + '/static/admin/js/templates/challenges/'+ obj['type_name'] +'/' + obj['type_name'] + '-challenge-update.hbs', function(template_data){
+ var template = Handlebars.compile(template_data);
+ $.get(script_root + '/static/admin/js/templates/challenges/'+ obj['type_name'] +'/' + obj['type_name'] + '-challenge-modals.hbs', function(template_data){
+ var template = Handlebars.compile(template_data);
+ $("#update-modals-entry-div").html(template({'nonce':$('#nonce').val(), 'script_root':script_root}));
+ });
+ $.ajax({
+ url: script_root + '/static/admin/js/templates/challenges/'+obj['type_name']+'/'+obj['type_name']+'-challenge-update.js',
+ dataType: "script",
+ success: success_cb,
+ cache: true,
});
});
}
-function updatekeys(){
- keys = [];
- vals = [];
- chal = $('#keys-chal').val()
- $('.current-key').each(function(){
- keys.push($(this).val());
- })
- $('#current-keys input[name*="key_type"]:checked').each(function(){
- vals.push($(this).val());
- })
- $.post(script_root + '/admin/keys/'+chal, {'keys':keys, 'vals':vals, 'nonce': $('#nonce').val()})
- loadchal(chal, true)
- $('#update-keys').modal('hide');
-}
-
-
-function deletekey(key_id){
- $.post(script_root + '/admin/keys/'+key_id+'/delete', {'nonce': $('#nonce').val()}, function(data){
- if (data == "1") {
- $('tr[name={0}]'.format(key_id)).remove();
- }
- });
-}
-
-function updatekey(){
- var key_id = $('#key-id').val();
- var chal = $('#keys-chal').val();
- var key_data = $('#key-data').val();
- var key_type = $('#key-type').val();
- var nonce = $('#nonce').val();
- $.post(script_root + '/admin/keys/'+key_id, {
- 'chal':chal,
- 'key':key_data,
- 'key_type': key_type,
- 'nonce': nonce
- }, function(data){
- if (data == "1") {
- loadkeys(chal);
- $('#edit-keys').modal('toggle');
- }
- })
-}
-
-function loadtags(chal){
- $('#tags-chal').val(chal)
- $('#current-tags').empty()
- $('#chal-tags').empty()
- $.get(script_root + '/admin/tags/'+chal, function(data){
- tags = $.parseJSON(JSON.stringify(data))
- tags = tags['tags']
- for (var i = 0; i < tags.length; i++) {
- tag = ""+tags[i].tag+"×"
- $('#current-tags').append(tag)
- };
- $('.delete-tag').click(function(e){
- deletetag(e.target.name)
- $(e.target).parent().remove()
- });
- });
-}
-
-function deletetag(tagid){
- $.post(script_root + '/admin/tags/'+tagid+'/delete', {'nonce': $('#nonce').val()});
-}
-
-
-function edithint(hintid){
- $.get(script_root + '/admin/hints/' + hintid, function(data){
- console.log(data);
- })
-}
-
-
-function deletehint(hintid){
- $.delete(script_root + '/admin/hints/' + hintid, function(data, textStatus, jqXHR){
- if (jqXHR.status == 204){
- var chalid = $('.chal-id').val();
- loadhints(chalid);
- }
- });
-}
-
-
-function loadhints(chal){
- $.get(script_root + '/admin/chal/{0}/hints'.format(chal), function(data){
- var table = $('#hintsboard > tbody');
- table.empty();
- for (var i = 0; i < data.hints.length; i++) {
- var hint = data.hints[i]
- var hint_row = "
" +
- "| {0} | ".format(hint.hint) +
- "{0} | ".format(hint.cost) +
- "" +
- "".format(hint.id)+
- "".format(hint.id)+
- " | " +
- "
";
- table.append(hint_row);
- }
- });
-}
-
-
-function deletechal(chalid){
- $.post(script_root + '/admin/chal/delete', {'nonce':$('#nonce').val(), 'id':chalid});
-}
-
-function updatetags(){
- tags = [];
- chal = $('#tags-chal').val()
- $('#chal-tags > span > span').each(function(i, e){
- tags.push($(e).text())
- });
- $.post(script_root + '/admin/tags/'+chal, {'tags':tags, 'nonce': $('#nonce').val()})
- loadchal(chal)
-}
-
-function updatefiles(){
- chal = $('#files-chal').val();
- var form = $('#update-files form')[0];
- var formData = new FormData(form);
- $.ajax({
- url: script_root + '/admin/files/'+chal,
- data: formData,
- type: 'POST',
- cache: false,
- contentType: false,
- processData: false,
- success: function(data){
- form.reset();
- loadfiles(chal);
- $('#update-files').modal('hide');
- }
- });
-}
-
-function loadfiles(chal){
- $('#update-files form').attr('action', script_root+'/admin/files/'+chal)
- $.get(script_root + '/admin/files/' + chal, function(data){
- $('#files-chal').val(chal)
- files = $.parseJSON(JSON.stringify(data));
- files = files['files']
- $('#current-files').empty()
- for(x=0; x'+''+filename+'Delete')
- }
- });
-}
-
-function deletefile(chal, file, elem){
- $.post(script_root + '/admin/files/' + chal,{
- 'nonce': $('#nonce').val(),
- 'method': 'delete',
- 'file': file
- }, function (data){
- if (data == "1") {
- elem.parent().remove()
- }
- });
-}
-
-
function loadchals(){
$('#challenges').empty();
$.post(script_root + "/admin/chals", {
@@ -310,11 +80,10 @@ function loadchals(){
};
$('#challenges button').click(function (e) {
- loadchal(this.value);
- loadkeys(this.value);
- loadhints(this.value);
- loadtags(this.value);
- loadfiles(this.value);
+ id = this.value
+ load_chal_template(id, function(){
+ openchal(id);
+ });
});
// $('.create-challenge').click(function (e) {
@@ -326,130 +95,6 @@ function loadchals(){
});
}
-$('#submit-key').click(function (e) {
- submitkey($('#chalid').val(), $('#answer').val())
-});
-
-$('#submit-keys').click(function (e) {
- e.preventDefault();
- $('#update-keys').modal('hide');
-});
-
-$('#submit-tags').click(function (e) {
- e.preventDefault();
- updatetags()
-});
-
-$('#submit-files').click(function (e) {
- e.preventDefault();
- updatefiles()
-});
-
-$('#delete-chal form').submit(function(e){
- e.preventDefault();
- $.post(script_root + '/admin/chal/delete', $(this).serialize(), function(data){
- console.log(data)
- if (data){
- loadchals();
- }
- else {
- alert('There was an error');
- }
- })
- $("#delete-chal").modal("hide");
- $("#update-challenge").modal("hide");
-});
-
-$(".tag-insert").keyup(function (e) {
- if (e.keyCode == 13) {
- tag = $('.tag-insert').val()
- tag = tag.replace(/'/g, '');
- if (tag.length > 0){
- tag = ""+tag+"×"
- $('#chal-tags').append(tag)
- }
- $('.tag-insert').val("")
- }
-});
-
-$('#limit_max_attempts').change(function() {
- if(this.checked) {
- $('#chal-attempts-group').show();
- } else {
- $('#chal-attempts-group').hide();
- $('#chal-attempts-input').val('');
- }
-});
-
-// 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}))
- }
-});
-
-// Open New Challenge modal when New Challenge button is clicked
-// $('.create-challenge').click(function (e) {
-// $('#create-challenge').modal();
-// });
-
-
-$('#create-key').click(function(e){
- $.get(script_root + '/admin/key_types', function(data){
- $("#create-keys-select").empty();
- var option = "";
- $("#create-keys-select").append(option);
- for (var key in data){
- var option = "".format(key, data[key]);
- $("#create-keys-select").append(option);
- }
- $("#create-keys").modal();
- });
-});
-
-$('#create-keys-select').change(function(){
- var key_type_name = $(this).find("option:selected").text();
-
- $.get(script_root + '/static/admin/js/templates/keys/'+key_type_name +'/'+key_type_name+'.hbs', function(template_data){
- var template = Handlebars.compile(template_data);
- $("#create-keys-entry-div").html(template());
- $("#create-keys-button-div").show();
- });
-});
-
-
-$('#create-keys-submit').click(function (e) {
- e.preventDefault();
- var chalid = $('#create-keys').find('.chal-id').val();
- var key_data = $('#create-keys').find('input[name=key]').val();
- var key_type = $('#create-keys-select').val();
- create_key(chalid, key_data, key_type);
-});
-
-
-$('#create-hint').click(function(e){
- e.preventDefault();
- load_hint_modal('create');
-});
-
-$('#hint-modal-submit').submit(function (e) {
- e.preventDefault();
- var params = {}
- $(this).serializeArray().map(function(x){
- params[x.name] = x.value;
- });
- $.post(script_root + $(this).attr('action'), params, function(data){
- loadhints(params['chal']);
- });
- $("#hint-modal").modal('hide');
-});
-
-
$(function(){
loadchals();
})
diff --git a/CTFd/static/admin/js/multi-modal.js b/CTFd/static/admin/js/multi-modal.js
index 37dd3b2b..0c4781d0 100644
--- a/CTFd/static/admin/js/multi-modal.js
+++ b/CTFd/static/admin/js/multi-modal.js
@@ -3,7 +3,6 @@
var MultiModal = function(element) {
this.$element = $(element);
- this.modalCount = 0;
};
MultiModal.BASE_ZINDEX = 1040;
@@ -11,30 +10,32 @@
MultiModal.prototype.show = function(target) {
var that = this;
var $target = $(target);
- var modalIndex = that.modalCount++;
+ var modalCount = $('.modal:visible').length;
- $target.css('z-index', MultiModal.BASE_ZINDEX + (modalIndex * 20) + 10);
+ $target.css('z-index', MultiModal.BASE_ZINDEX + (modalCount * 20) + 10);
window.setTimeout(function() {
- if(modalIndex > 0)
+ var modalCount = $('.modal:visible').length;
+ if(modalCount > 0)
$('.modal-backdrop').not(':first').addClass('hidden');
- that.adjustBackdrop();
+ that.adjustBackdrop(modalCount);
});
};
MultiModal.prototype.hidden = function(target) {
- this.modalCount--;
+ var modalCount = $('.modal:visible').length;
- if(this.modalCount) {
- this.adjustBackdrop();
+ var $target = $(target);
+
+ if(modalCount) {
+ this.adjustBackdrop(modalCount - 1);
$('body').addClass('modal-open');
}
};
- MultiModal.prototype.adjustBackdrop = function() {
- var modalIndex = this.modalCount - 1;
- $('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + (modalIndex * 20));
+ MultiModal.prototype.adjustBackdrop = function(modalCount) {
+ $('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + ((modalCount)* 20));
};
function Plugin(method, target) {
diff --git a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-modals.hbs b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-modals.hbs
new file mode 100644
index 00000000..09ccb2f8
--- /dev/null
+++ b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-modals.hbs
@@ -0,0 +1,409 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Hint |
+ Cost |
+ Settings |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Hint |
+ Cost |
+ Settings |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-update.hbs b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-update.hbs
new file mode 100644
index 00000000..e69de29b
diff --git a/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-update.js b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-update.js
new file mode 100644
index 00000000..650d409e
--- /dev/null
+++ b/CTFd/static/admin/js/templates/challenges/standard/standard-challenge-update.js
@@ -0,0 +1,390 @@
+//http://stackoverflow.com/a/2648463 - wizardry!
+String.prototype.format = String.prototype.f = function() {
+ var s = this,
+ i = arguments.length;
+
+ while (i--) {
+ s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
+ }
+ return s;
+};
+
+function load_hint_modal(method, hintid){
+ $('#hint-modal-hint').val('');
+ $('#hint-modal-cost').val('');
+ if (method == 'create'){
+ $('#hint-modal-submit').attr('action', '/admin/hints');
+ $('#hint-modal-title').text('Create Hint');
+ $("#hint-modal").modal();
+ } else if (method == 'update'){
+ $.get(script_root + '/admin/hints/' + hintid, function(data){
+ $('#hint-modal-submit').attr('action', '/admin/hints/' + hintid);
+ $('#hint-modal-hint').val(data.hint);
+ $('#hint-modal-cost').val(data.cost);
+ $('#hint-modal-title').text('Update Hint');
+ $("#hint-modal-button").text('Update Hint');
+ $("#hint-modal").modal();
+ });
+ }
+}
+
+function submitkey(chal, key) {
+ $.post(script_root + "/admin/chal/" + chal, {
+ key: key,
+ nonce: $('#nonce').val()
+ }, function (data) {
+ alert(data)
+ })
+}
+
+function create_key(chal, key, key_type) {
+ $.post(script_root + "/admin/keys", {
+ chal: chal,
+ key: key,
+ key_type: key_type,
+ nonce: $('#nonce').val()
+ }, function (data) {
+ if (data == "1"){
+ loadkeys(chal);
+ $("#create-keys").modal('toggle');
+ }
+ });
+}
+
+function loadkeys(chal){
+ $.get(script_root + '/admin/chal/' + chal + '/keys', function(data){
+ $('#keys-chal').val(chal);
+ keys = $.parseJSON(JSON.stringify(data));
+ keys = keys['keys'];
+ $('#current-keys').empty();
+ $.get(script_root + "/static/admin/js/templates/admin-keys-table.hbs", function(data){
+ var template = Handlebars.compile(data);
+ var wrapper = {keys: keys, script_root: script_root};
+ $('#current-keys').append(template(wrapper));
+ });
+ });
+}
+
+function updatekeys(){
+ keys = [];
+ vals = [];
+ chal = $('#keys-chal').val()
+ $('.current-key').each(function(){
+ keys.push($(this).val());
+ })
+ $('#current-keys input[name*="key_type"]:checked').each(function(){
+ vals.push($(this).val());
+ })
+ $.post(script_root + '/admin/keys/'+chal, {'keys':keys, 'vals':vals, 'nonce': $('#nonce').val()})
+ loadchal(chal, true)
+ $('#update-keys').modal('hide');
+}
+
+
+function deletekey(key_id){
+ $.post(script_root + '/admin/keys/'+key_id+'/delete', {'nonce': $('#nonce').val()}, function(data){
+ if (data == "1") {
+ $('tr[name={0}]'.format(key_id)).remove();
+ }
+ });
+}
+
+function updatekey(){
+ var key_id = $('#key-id').val();
+ var chal = $('#keys-chal').val();
+ var key_data = $('#key-data').val();
+ var key_type = $('#key-type').val();
+ var nonce = $('#nonce').val();
+ $.post(script_root + '/admin/keys/'+key_id, {
+ 'chal':chal,
+ 'key':key_data,
+ 'key_type': key_type,
+ 'nonce': nonce
+ }, function(data){
+ if (data == "1") {
+ loadkeys(chal);
+ $('#edit-keys').modal('toggle');
+ }
+ })
+}
+
+function loadtags(chal){
+ $('#tags-chal').val(chal)
+ $('#current-tags').empty()
+ $('#chal-tags').empty()
+ $.get(script_root + '/admin/tags/'+chal, function(data){
+ tags = $.parseJSON(JSON.stringify(data))
+ tags = tags['tags']
+ for (var i = 0; i < tags.length; i++) {
+ tag = ""+tags[i].tag+"×"
+ $('#current-tags').append(tag)
+ };
+ $('.delete-tag').click(function(e){
+ deletetag(e.target.name)
+ $(e.target).parent().remove()
+ });
+ });
+}
+
+function deletetag(tagid){
+ $.post(script_root + '/admin/tags/'+tagid+'/delete', {'nonce': $('#nonce').val()});
+}
+
+
+function edithint(hintid){
+ $.get(script_root + '/admin/hints/' + hintid, function(data){
+ console.log(data);
+ })
+}
+
+
+function deletehint(hintid){
+ $.delete(script_root + '/admin/hints/' + hintid, function(data, textStatus, jqXHR){
+ if (jqXHR.status == 204){
+ var chalid = $('.chal-id').val();
+ loadhints(chalid);
+ }
+ });
+}
+
+
+function loadhints(chal){
+ $.get(script_root + '/admin/chal/{0}/hints'.format(chal), function(data){
+ var table = $('#hintsboard > tbody');
+ table.empty();
+ for (var i = 0; i < data.hints.length; i++) {
+ var hint = data.hints[i]
+ var hint_row = "" +
+ "| {0} | ".format(hint.hint) +
+ "{0} | ".format(hint.cost) +
+ "" +
+ "".format(hint.id)+
+ "".format(hint.id)+
+ " | " +
+ "
";
+ table.append(hint_row);
+ }
+ });
+}
+
+
+function deletechal(chalid){
+ $.post(script_root + '/admin/chal/delete', {'nonce':$('#nonce').val(), 'id':chalid});
+}
+
+function updatetags(){
+ tags = [];
+ chal = $('#tags-chal').val()
+ $('#chal-tags > span > span').each(function(i, e){
+ tags.push($(e).text())
+ });
+ $.post(script_root + '/admin/tags/'+chal, {'tags':tags, 'nonce': $('#nonce').val()})
+ loadchal(chal)
+}
+
+function updatefiles(){
+ chal = $('#files-chal').val();
+ var form = $('#update-files form')[0];
+ var formData = new FormData(form);
+ $.ajax({
+ url: script_root + '/admin/files/'+chal,
+ data: formData,
+ type: 'POST',
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(data){
+ form.reset();
+ loadfiles(chal);
+ $('#update-files').modal('hide');
+ }
+ });
+}
+
+function loadfiles(chal){
+ $('#update-files form').attr('action', script_root+'/admin/files/'+chal)
+ $.get(script_root + '/admin/files/' + chal, function(data){
+ $('#files-chal').val(chal)
+ files = $.parseJSON(JSON.stringify(data));
+ files = files['files']
+ $('#current-files').empty()
+ for(x=0; x'+''+filename+'Delete')
+ }
+ });
+}
+
+function deletefile(chal, file, elem){
+ $.post(script_root + '/admin/files/' + chal,{
+ 'nonce': $('#nonce').val(),
+ 'method': 'delete',
+ 'file': file
+ }, function (data){
+ if (data == "1") {
+ elem.parent().remove()
+ }
+ });
+}
+
+$('#submit-key').click(function (e) {
+ submitkey($('#chalid').val(), $('#answer').val())
+});
+
+$('#submit-keys').click(function (e) {
+ e.preventDefault();
+ $('#update-keys').modal('hide');
+});
+
+$('#submit-tags').click(function (e) {
+ e.preventDefault();
+ updatetags()
+});
+
+$('#submit-files').click(function (e) {
+ e.preventDefault();
+ updatefiles()
+});
+
+$('#delete-chal form').submit(function(e){
+ e.preventDefault();
+ $.post(script_root + '/admin/chal/delete', $(this).serialize(), function(data){
+ console.log(data)
+ if (data){
+ loadchals();
+ }
+ else {
+ alert('There was an error');
+ }
+ })
+ $("#delete-chal").modal("hide");
+ $("#update-challenge").modal("hide");
+});
+
+$(".tag-insert").keyup(function (e) {
+ if (e.keyCode == 13) {
+ tag = $('.tag-insert').val()
+ tag = tag.replace(/'/g, '');
+ if (tag.length > 0){
+ tag = ""+tag+"×"
+ $('#chal-tags').append(tag)
+ }
+ $('.tag-insert').val("")
+ }
+});
+
+$('#limit_max_attempts').change(function() {
+ if(this.checked) {
+ $('#chal-attempts-group').show();
+ } else {
+ $('#chal-attempts-group').hide();
+ $('#chal-attempts-input').val('');
+ }
+});
+
+// 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}))
+ }
+});
+
+// Open New Challenge modal when New Challenge button is clicked
+// $('.create-challenge').click(function (e) {
+// $('#create-challenge').modal();
+// });
+
+
+$('#create-key').click(function(e){
+ $.get(script_root + '/admin/key_types', function(data){
+ $("#create-keys-select").empty();
+ var option = "";
+ $("#create-keys-select").append(option);
+ for (var key in data){
+ var option = "".format(key, data[key]);
+ $("#create-keys-select").append(option);
+ }
+ $("#create-keys").modal();
+ });
+});
+
+$('#create-keys-select').change(function(){
+ var key_type_name = $(this).find("option:selected").text();
+
+ $.get(script_root + '/static/admin/js/templates/keys/'+key_type_name +'/'+key_type_name+'.hbs', function(template_data){
+ var template = Handlebars.compile(template_data);
+ $("#create-keys-entry-div").html(template());
+ $("#create-keys-button-div").show();
+ });
+});
+
+
+$('#create-keys-submit').click(function (e) {
+ e.preventDefault();
+ var chalid = $('#create-keys').find('.chal-id').val();
+ var key_data = $('#create-keys').find('input[name=key]').val();
+ var key_type = $('#create-keys-select').val();
+ create_key(chalid, key_data, key_type);
+});
+
+
+$('#create-hint').click(function(e){
+ e.preventDefault();
+ load_hint_modal('create');
+});
+
+$('#hint-modal-submit').submit(function (e) {
+ e.preventDefault();
+ var params = {}
+ $(this).serializeArray().map(function(x){
+ params[x.name] = x.value;
+ });
+ $.post(script_root + $(this).attr('action'), params, function(data){
+ loadhints(params['chal']);
+ });
+ $("#hint-modal").modal('hide');
+});
+
+function loadchal(id, update) {
+ // $('#chal *').show()
+ // $('#chal > h1').hide()
+ obj = $.grep(challenges['game'], function (e) {
+ return e.id == id;
+ })[0]
+ $('#desc-write-link').click() // Switch to Write tab
+ $('.chal-title').text(obj.name);
+ $('.chal-name').val(obj.name);
+ $('.chal-desc').val(obj.description);
+ $('.chal-value').val(obj.value);
+ if (parseInt(obj.max_attempts) > 0){
+ $('.chal-attempts').val(obj.max_attempts);
+ $('#limit_max_attempts').prop('checked', true);
+ $('#chal-attempts-group').show();
+ }
+ $('.chal-category').val(obj.category);
+ $('.chal-id').val(obj.id);
+ $('.chal-hidden').prop('checked', false);
+ if (obj.hidden) {
+ $('.chal-hidden').prop('checked', true);
+ }
+ //$('#update-challenge .chal-delete').attr({
+ // 'href': '/admin/chal/close/' + (id + 1)
+ //})
+ if (typeof update === 'undefined')
+ $('#update-challenge').modal();
+}
+
+function openchal(id){
+ loadchal(id);
+ loadkeys(id);
+ loadhints(id);
+ loadtags(id);
+ loadfiles(id);
+}
+
diff --git a/CTFd/static/admin/js/utils.js b/CTFd/static/admin/js/utils.js
index 1dc99fba..bb47551f 100644
--- a/CTFd/static/admin/js/utils.js
+++ b/CTFd/static/admin/js/utils.js
@@ -79,4 +79,4 @@ jQuery.each(["put", "delete"], function(i, method) {
success: callback
});
};
-});
\ No newline at end of file
+});
diff --git a/CTFd/templates/admin/chals.html b/CTFd/templates/admin/chals.html
index 1f5028ee..45408f1f 100644
--- a/CTFd/templates/admin/chals.html
+++ b/CTFd/templates/admin/chals.html
@@ -31,338 +31,11 @@
New Challenge
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- | Hint |
- Cost |
- Settings |
-
-
-
-
-
-
-
-
-
-
-
-