Updated CTFd UI to use Bootstrap; makes viewing and adding challenges

much more visually appealing
selenium-screenshot-testing
Christopher Thompson 2016-02-01 01:01:25 -05:00
parent ac6e5b8c4f
commit b501561551
32 changed files with 1876 additions and 902 deletions

View File

@ -196,7 +196,7 @@ def delete_page(pageroute):
def admin_chals():
if request.method == 'POST':
chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category').order_by(Challenges.value).all()
json_data = {'game':[]}
for x in chals:
json_data['game'].append({'id':x[1], 'name':x[2], 'value':x[3], 'description':x[4], 'category':x[5]})
@ -228,7 +228,7 @@ def admin_keys(chalid):
flag_dict = {'flag':flag, 'type':int(val)}
flags.append(flag_dict)
json_data = json.dumps(flags)
chal.flags = json_data
db.session.commit()
@ -293,7 +293,7 @@ def admin_files(chalid):
if len(filename) <= 0:
continue
md5hash = hashlib.md5(os.urandom(64)).hexdigest()
if not os.path.exists(os.path.join(os.path.normpath(app.static_folder), 'uploads', md5hash)):
@ -433,7 +433,7 @@ def admin_graph(graph_type):
return jsonify(json_data)
elif graph_type == "solves":
solves = Solves.query.add_columns(db.func.count(Solves.chalid)).group_by(Solves.chalid).all()
json_data = {}
json_data = {}
for chal, count in solves:
json_data[chal.chal.name] = count
return jsonify(json_data)
@ -489,7 +489,7 @@ def delete_solve(teamid, chalid):
@admins_only
def admin_stats():
db.session.commit()
teams_registered = db.session.query(db.func.count(Teams.id)).first()[0]
wrong_count = db.session.query(db.func.count(WrongKeys.id)).first()[0]
solve_count = db.session.query(db.func.count(Solves.id)).first()[0]

View File

@ -73,7 +73,7 @@ table{
}
#keys-pie-graph{
width: 400px;
width: 600px;
max-height: 330px;
float: left;
}
@ -86,16 +86,14 @@ table{
.chal-button{
width: 150px;
color: white;
border: None;
}
.chal-button > p{
font-family: monospace;
.chal-button > p {
margin-bottom: 0px;
height: 20px;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chal-button > span{

View File

@ -21,7 +21,7 @@ String.prototype.hashCode = function() {
return hash;
};
function loadchal(id) {
function loadchal(id, update) {
// $('#chal *').show()
// $('#chal > h1').hide()
obj = $.grep(challenges['game'], function (e) {
@ -37,8 +37,8 @@ function loadchal(id) {
//$('#update-challenge .chal-delete').attr({
// 'href': '/admin/chal/close/' + (id + 1)
//})
$('#update-challenge').foundation('reveal', 'open');
if (typeof update === 'undefined')
$('#update-challenge').modal();
}
function submitkey(chal, key) {
@ -57,12 +57,13 @@ function loadkeys(chal){
keys = keys['keys'];
$('#current-keys').empty();
for(x=0; x<keys.length; x++){
var elem = $('<div>');
elem.append($("<input class='current-key' type='text'>").val(keys[x].key));
elem.append('<input type="radio" name="key_type['+x+']" value="0">Static');
elem.append('<input type="radio" name="key_type['+x+']" value="1">Regex');
elem.append('<a href="#" onclick="$(this).parent().remove()" class="remove-key">Remove</a>');
var elem = $('<div class="col-md-4">');
elem.append($("<div class='form-group'>").append($("<input class='current-key form-control' type='text'>").val(keys[x].key)));
elem.append('<div class="radio-inline"><input type="radio" name="key_type['+x+']" value="0">Static</div>');
elem.append('<div class="radio-inline"><input type="radio" name="key_type['+x+']" value="1">Regex</div>');
elem.append('<a href="#" onclick="$(this).parent().remove()" class="btn btn-danger key-remove-button">Remove</a>');
$('#current-keys').append(elem);
$('#current-keys input[name="key_type['+x+']"][value="'+keys[x].type+'"]').prop('checked',true);
}
@ -80,7 +81,8 @@ function updatekeys(){
vals.push($(this).val());
})
$.post('/admin/keys/'+chal, {'keys':keys, 'vals':vals, 'nonce': $('#nonce').val()})
loadchal(chal)
loadchal(chal, true)
$('#update-keys').modal('hide');
}
function loadtags(chal){
@ -91,7 +93,7 @@ function loadtags(chal){
tags = $.parseJSON(JSON.stringify(data))
tags = tags['tags']
for (var i = 0; i < tags.length; i++) {
tag = "<span class='secondary label chal-tag'><span>"+tags[i].tag+"</span><a name='"+tags[i].id+"'' class='delete-tag'>&#215;</a></span>"
tag = "<span class='label label-primary chal-tag'><span>"+tags[i].tag+"</span><a name='"+tags[i].id+"'' class='delete-tag'>&#215;</a></span>"
$('#current-tags').append(tag)
};
$('.delete-tag').click(function(e){
@ -120,7 +122,7 @@ function updatetags(){
}
function loadfiles(chal){
$('#update-files > form').attr('action', '/admin/files/'+chal)
$('#update-files form').attr('action', '/admin/files/'+chal)
$.get('/admin/files/' + chal, function(data){
$('#files-chal').val(chal)
files = $.parseJSON(JSON.stringify(data));
@ -129,7 +131,7 @@ function loadfiles(chal){
for(x=0; x<files.length; x++){
filename = files[x].file.split('/')
filename = filename[filename.length - 1]
$('#current-files').append('<div data-alert class="alert-box info radius">'+'<a href=/'+files[x].file+'>'+filename+'</a><a href="#" onclick="deletefile('+chal+','+files[x].id+', $(this))" value="'+files[x].id+'" style="float:right;">Delete</a></div>')
$('#current-files').append('<div class="row" style="margin:5px 0px;">'+'<a style="position:relative;top:10px;" href=/'+files[x].file+'>'+filename+'</a><a href="#" class="btn btn-danger" onclick="deletefile('+chal+','+files[x].id+', $(this))" value="'+files[x].id+'" style="float:right;">Delete</a></div>')
}
});
}
@ -137,7 +139,7 @@ function loadfiles(chal){
function deletefile(chal, file, elem){
$.post('/admin/files/' + chal,{
'nonce': $('#nonce').val(),
'method': 'delete',
'method': 'delete',
'file': file
}, function (data){
if (data == "1") {
@ -159,13 +161,13 @@ function loadchals(){
for (var i = challenges['game'].length - 1; i >= 0; i--) {
if ($.inArray(challenges['game'][i].category, categories) == -1) {
categories.push(challenges['game'][i].category)
$('#challenges').append($('<tr id="' + challenges['game'][i].category.replace(/ /g,"-").hashCode() + '"><td class="large-2"><h3>' + challenges['game'][i].category + '</h3></td></tr>'))
$('#challenges').append($('<tr id="' + challenges['game'][i].category.replace(/ /g,"-").hashCode() + '"><td class="col-md-1"><h3>' + challenges['game'][i].category + '</h3></td></tr>'))
}
};
for (var i = 0; i <= challenges['game'].length - 1; i++) {
var chal = challenges['game'][i]
var chal_button = $('<button class="chal-button" value="{0}"><p>{1}</p><span>{2}</span></button>'.format(chal.id, chal.name, chal.value))
var chal_button = $('<button class="chal-button col-md-2 theme-background" value="{0}"><p>{1}</p><span>{2}</span></button>'.format(chal.id, chal.name, chal.value))
$('#' + challenges['game'][i].category.replace(/ /g,"-").hashCode()).append(chal_button);
};
@ -179,7 +181,7 @@ function loadchals(){
$('.create-challenge').click(function (e) {
$('#new-chal-category').val($($(this).siblings()[0]).text().trim())
$('#new-chal-title').text($($(this).siblings()[0]).text().trim())
$('#new-challenge').foundation('reveal', 'open');
$('#new-challenge').modal();
});
});
@ -190,25 +192,28 @@ $('#submit-key').click(function (e) {
});
$('#submit-keys').click(function (e) {
e.preventDefault();
updatekeys()
});
$('#submit-tags').click(function (e) {
e.preventDefault();
updatetags()
});
$('#delete-chal > form').submit(function(e){
$('#delete-chal form').submit(function(e){
e.preventDefault();
$.post('/admin/chal/delete', $(this).serialize(), function(data){
console.log(data)
if (data){
loadchals();
$('#delete-chal').foundation('reveal', 'close');
}
else {
alert('There was an error');
}
})
$("#delete-chal").modal("hide");
$("#update-challenge").modal("hide");
});
$(".tag-insert").keyup(function (e) {
@ -216,7 +221,7 @@ $(".tag-insert").keyup(function (e) {
tag = $('.tag-insert').val()
tag = tag.replace(/'/g, '');
if (tag.length > 0){
tag = "<span class='secondary label chal-tag'><span>"+tag+"</span><a onclick='$(this).parent().remove()'>&#215;</a></span>"
tag = "<span class='label label-primary chal-tag'><span>"+tag+"</span><a class='delete-tag' onclick='$(this).parent().remove()'>&#215;</a></span>"
$('#chal-tags').append(tag)
}
$('.tag-insert').val("")
@ -226,34 +231,33 @@ $(".tag-insert").keyup(function (e) {
// Markdown Preview
$('#desc-edit').on('toggled', function (event, tab) {
if (tab[0].id == 'desc-preview'){
$(tab[0]).html(marked($('#desc-editor').val(), {'gfm':true, 'breaks':true}))
$('#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('toggled', function (event, tab) {
if (tab[0].id == 'new-desc-preview'){
$(tab[0]).html(marked($('#new-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').foundation('reveal', 'open');
$('#create-challenge').modal();
});
$('#create-key').click(function(e){
var amt = $('#current-keys input[type=text]').length
// $('#current-keys').append("<input class='current-key' type='text' placeholder='Blank Key'>");
// $('#current-keys').append('<input type="radio" name="key_type[{0}]" value="0">Static'.format(amt));
// $('#current-keys').append('<input type="radio" name="key_type[{0}]" value="1">Regex'.format(amt));
var elem = $('<div>');
elem.append("<input class='current-key' type='text' placeholder='Blank Key'>");
elem.append('<input type="radio" name="key_type[{0}]" value="0" checked="checked">Static'.format(amt));
elem.append('<input type="radio" name="key_type[{0}]" value="1">Regex'.format(amt));
elem.append('<a href="#" onclick="$(this).parent().remove()" class="remove-key">Remove</a>');
var elem = $('<div class="col-md-4">');
elem.append($("<div class='form-group'>").append($("<input class='current-key form-control' type='text'>")));
elem.append('<div class="radio-inline"><input type="radio" name="key_type['+amt+']" value="0">Static</div>');
elem.append('<div class="radio-inline"><input type="radio" name="key_type['+amt+']" value="1">Regex</div>');
elem.append('<a href="#" onclick="$(this).parent().remove()" class="btn btn-danger key-remove-button">Remove</a>');
$('#current-keys').append(elem);
});

View File

@ -0,0 +1,63 @@
(function($, window) {
'use strict';
var MultiModal = function(element) {
this.$element = $(element);
this.modalCount = 0;
};
MultiModal.BASE_ZINDEX = 1040;
MultiModal.prototype.show = function(target) {
var that = this;
var $target = $(target);
var modalIndex = that.modalCount++;
$target.css('z-index', MultiModal.BASE_ZINDEX + (modalIndex * 20) + 10);
window.setTimeout(function() {
if(modalIndex > 0)
$('.modal-backdrop').not(':first').addClass('hidden');
that.adjustBackdrop();
});
};
MultiModal.prototype.hidden = function(target) {
this.modalCount--;
if(this.modalCount) {
this.adjustBackdrop();
$('body').addClass('modal-open');
}
};
MultiModal.prototype.adjustBackdrop = function() {
var modalIndex = this.modalCount - 1;
$('.modal-backdrop:first').css('z-index', MultiModal.BASE_ZINDEX + (modalIndex * 20));
};
function Plugin(method, target) {
return this.each(function() {
var $this = $(this);
var data = $this.data('multi-modal-plugin');
if(!data)
$this.data('multi-modal-plugin', (data = new MultiModal(this)));
if(method)
data[method](target);
});
}
$.fn.multiModal = Plugin;
$.fn.multiModal.Constructor = MultiModal;
$(document).on('show.bs.modal', function(e) {
$(document).multiModal('show', e.target);
});
$(document).on('hidden.bs.modal', function(e) {
$(document).multiModal('hidden', e.target);
});
}(jQuery, window));

132
CTFd/static/css/input.css Normal file
View File

@ -0,0 +1,132 @@
.submit-row {
padding-left: 15px;
padding-right: 30px;
}
.input {
width: 100%;
position: relative;
z-index: 1;
display: inline-block;
margin: 1em 0em;
vertical-align: top;
}
.input-field {
position: relative;
display: block;
float: right;
padding: 0.8em;
width: 60%;
border: none;
border-radius: 0;
background: #f0f0f0;
color: #aaa;
font-weight: 400;
font-family: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-appearance: none; /* for box shadows to show on iOS */
}
.input-field:focus {
outline: none;
}
.input-label {
display: inline-block;
float: right;
padding: 0 1em;
width: 40%;
color: #6a7989;
font-weight: bold;
font-size: 100%;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.label-content {
position: relative;
display: block;
padding: 1.6em 0;
width: 100%;
}
.graphic {
position: absolute;
top: 0;
left: 0;
fill: none;
}
.icon {
color: #ddd;
font-size: 150%;
}
.input-field {
width: 100%;
background-color: #eee;
border: 2px solid transparent;
-webkit-transition: background-color 0.3s, border-color 0.3s;
transition: background-color 0.3s, border-color 0.3s;
}
.input-label {
width: 100%;
text-align: left;
position: absolute;
bottom: 100%;
pointer-events: none;
overflow: hidden;
padding: 0 1.25em;
-webkit-transform: translate3d(0, 3em, 0);
transform: translate3d(0, 3em, 0);
-webkit-transition: -webkit-transform 0.3s;
transition: transform 0.3s;
}
.label-content {
color: #8B8C8B;
padding: 0.25em 0;
-webkit-transition: -webkit-transform 0.3s;
transition: transform 0.3s;
}
.label-content::after {
content: attr(data-content);
position: absolute;
font-weight: 800;
bottom: 100%;
left: 0;
height: 100%;
width: 100%;
color: #a3d39c;
padding: 0.25em 0;
letter-spacing: 1px;
font-size: 0.85em;
}
.input-field:focus + .input-field,
.input--filled .input-field {
background-color: transparent;
border-color: #a3d39c;
}
.input--hide {
display: none;
}
#submit {
position: relative;
right: -15px;
}
.done-row {
margin: 0px;
}

View File

@ -0,0 +1,236 @@
html, body, .container {
height: 100% !important;
font-family: 'Lato', sans-serif;
}
h1, h2 {
font-family: 'Raleway', sans-serif;
font-weight: 500;
letter-spacing: 2px;
}
td {
padding: 15px !important;
}
a {
outline: 0;
}
.no-margin-right {
margin-right: 0px !important;
}
.no-margin-left {
margin-left: -3px !important;
}
.navbar > .container {
padding-top: 30px;
}
.navbar .navbar-brand {
font-size: 24px;
letter-spacing: -0.04rem;
line-height: 15px;
color: #FFF;
}
.navbar-inverse .navbar-nav > li > a {
color: #FFF !important;
}
.navbar li > a {
opacity: 0.5;
transition: opacity 0.08s ease-in 0s;
cursor: pointer;
}
.navbar li > a:hover {
opacity: 0.8;
}
.align-text-to-button {
padding-top: 16px;
}
.padded-container {
margin-top: 50px;
padding-left: 50px;
padding-right: 50px;
}
.main-container {
margin-top: 35px;
margin-bottom: 25px;
}
#login-container {
padding-left: 70px;
padding-right: 70px;
}
#chal > form{
width: 400px;
margin: 0 auto;
}
.reveal-modal{
text-align: center;
}
.chal-desc{
text-align: left;
}
table{
width: 100%;
}
#challenges button{
margin: 8px;
}
.row > h1{
text-align: center;
}
#challenges{
line-height: 66px;
}
#score-graph{
max-height: 400px;
}
#keys-pie-graph{
width: 50%;
max-height: 330px;
float: left;
}
#categories-pie-graph{
width: 50%;
float: left;
max-height: 330px;
}
.logo{
margin: 0 auto;
width: 500px;
padding: 50px;
display: block;
}
@media only screen and (min-width: 40.063em){
.top-bar .dropdown{
display: block;
padding: 0 15px 5px;
width: 200% !important;
}
}
.btn {
letter-spacing: 1px;
text-decoration: none;
background: none;
-moz-user-select: none;
background-image: none;
border: 1px solid transparent;
border-radius: 0;
cursor: pointer;
display: inline-block;
margin-bottom: 0;
vertical-align: middle;
white-space: nowrap;
font-size:14px;
line-height:20px;
font-weight:700;
text-transform:uppercase;
border: 3px solid;
padding:8px 20px;
}
.btn-outlined {
border-radius: 0;
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
transition: all 0.3s;
}
.file-wrapper {
background-color: #5B7290;
}
.file-wrapper:hover {
background-color: #747474;
}
.theme-background {
background-color: #545454 !important;
}
.solved-challenge {
background-color: #8EDC9D !important;
}
.panel-theme {
border-color: #545454;
}
.panel-theme > .panel-heading {
border-color: #545454;
background-color: #545454;
opacity: 1;
color: #FFF;
text-align: center;
}
.btn-outlined.btn-theme {
background: none;
color: #545454;
border-color: #545454;
}
.btn-outlined.btn-theme:hover,
.btn-outlined.btn-theme:active {
color: #FFF;
background: #545454;
border-color: #545454;
}
.navbar-inverse {
background: none repeat scroll 0% 0% #545454;
border: medium none;
margin-bottom: 0px;
}
.jumbotron {
background-color: #545454;
color: #FFF;
padding: 0px 0px 25px;
}
.jumbotron.home {
text-align: center;
margin-bottom: 0px;
}
.home h1 {
font-size: 48px !important;
}
.navbar {
border-radius: 0px;
}
.modal-content {
border-radius: 0px;
}
.alert {
border-radius: 0px;
}

View File

@ -1,129 +0,0 @@
#chal > form{
width: 400px;
margin: 0 auto;
}
.reveal-modal{
text-align: center;
}
.chal-desc{
text-align: left;
}
table{
width: 100%;
}
/*Not sure why foundation needs these two...*/
.top-bar input{
height: auto;
padding-top: 0.35rem;
padding-bottom: 0.35rem;
font-size: 0.75rem;
}
.top-bar .button{
padding-top: 0.45rem;
padding-bottom: 0.35rem;
margin-bottom: 0;
font-size: 0.75rem;
}
.dropdown{
background-color: #333 !important;
padding: 5px;
}
.dropdown button{
padding-top: 0.45rem;
padding-bottom: 0.35rem;
margin-bottom: 0;
font-size: 0.75rem;
}
#challenges button{
margin: 8px;
}
.row > h1{
text-align: center;
}
#challenges{
line-height: 66px;
}
#score-graph{
max-height: 400px;
clear:both;
}
.dropdown{
padding: 20px;
}
.dropdown input{
margin: 5px auto;
width: 95%;
}
.dropdown button{
margin: 10px auto;
width: 100%;
}
#keys-pie-graph{
width: 50%;
max-height: 330px;
float: left;
}
#categories-pie-graph{
width: 50%;
float: left;
max-height: 330px;
}
.logo{
margin: 0 auto;
width: 500px;
padding: 50px;
display: block;
}
.chal-button{
width: 150px;
}
.chal-button > p{
font-family: monospace;
margin-bottom: 0px;
height: 20px;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chal-button > span{
font-size: 14px;
}
@media only screen and (min-width: 40.063em){
.top-bar .dropdown{
display: block;
padding: 0 15px 5px;
width: 200% !important;
}
}
.top-bar input{
padding: 10px;
}
.scroll-wrap{
height: 400px;
overflow-y: auto;
overflow-x: hidden;
}

View File

@ -1,3 +1,4 @@
//http://stackoverflow.com/a/2648463 - wizardry!
String.prototype.format = String.prototype.f = function() {
var s = this,
@ -30,58 +31,43 @@ var challenges;
function loadchal(id) {
obj = $.grep(challenges['game'], function (e) {
return e.id == id;
})[0]
window.location.hash = obj.name
$('#chal-window .chal-name').text(obj.name)
$('#chal-window .chal-desc').html(marked(obj.description, {'gfm':true, 'breaks':true}))
})[0];
updateChalWindow(obj);
}
function loadchalbyname(chalname) {
obj = $.grep(challenges['game'], function (e) {
return e.name == chalname;
})[0];
updateChalWindow(obj);
}
function updateChalWindow(obj) {
window.location.hash = obj.name
$('#chal-window').find('.chal-name').text(obj.name)
$('#chal-window').find('.chal-desc').html(marked(obj.description, {'gfm':true, 'breaks':true}))
$('#chal-window').find('.chal-files').empty();
for (var i = 0; i < obj.files.length; i++) {
filename = obj.files[i].split('/')
filename = filename[filename.length - 1]
$('#chal-window .chal-desc').append("<a href='"+obj.files[i]+"'>"+filename+"</a><br/>")
$('#chal-window').find('.chal-files').append("<div class='col-md-3 file-button-wrapper'><a class='file-button' href='"+obj.files[i]+"'><label class='challenge-wrapper file-wrapper hide-text'>"+filename+"</label></a></div>")
};
$('#chal-window .chal-value').text(obj.value)
$('#chal-window .chal-category').text(obj.category)
$('#chal-window #chal-id').val(obj.id)
$('#chal-window .chal-solves').text(obj.solves + " solves")
$('#chal-window').find('.chal-value').text(obj.value)
$('#chal-window').find('.chal-category').text(obj.category)
$('#chal-window').find('#chal-id').val(obj.id)
var solves = obj.solves == 1 ? " Solve" : " Solves";
$('#chal-window').find('.chal-solves').text(obj.solves + solves)
$('#answer').val("")
$('pre code').each(function(i, block) {
hljs.highlightBlock(block);
});
$('#chal-window').foundation('reveal', 'open');
}
function loadchalbyname(chalname) {
obj = $.grep(challenges['game'], function (e) {
return e.name == chalname;
})[0]
window.location.hash = obj.name
$('#chal-window .chal-name').text(obj.name)
$('#chal-window .chal-desc').html(marked(obj.description, {'gfm':true, 'breaks':true}))
for (var i = 0; i < obj.files.length; i++) {
filename = obj.files[i].split('/')
filename = filename[filename.length - 1]
$('#chal-window .chal-desc').append("<a href='"+obj.files[i]+"'>"+filename+"</a><br/>")
};
$('#chal-window .chal-value').text(obj.value)
$('#chal-window .chal-category').text(obj.category)
$('#chal-window #chal-id').val(obj.id)
$('#chal-window .chal-solves').text(obj.solves + " solves")
$('#answer').val("")
$('pre code').each(function(i, block) {
hljs.highlightBlock(block);
});
$('#chal-window').foundation('reveal', 'open');
}
$("#answer").keyup(function(event){
$("#answer-input").keyup(function(event){
if(event.keyCode == 13){
$("#submit-key").click();
}
@ -89,8 +75,10 @@ $("#answer").keyup(function(event){
function submitkey(chal, key, nonce) {
$('#submit-key').addClass("disabled-button");
$('#submit-key').prop('disabled', true);
$.post("/chal/" + chal, {
key: key,
key: key,
nonce: nonce
}, function (data) {
if (data == -1){
@ -98,37 +86,37 @@ function submitkey(chal, key, nonce) {
return
}
else if (data == 0){ // Incorrect key
$('#submit-key').text('Incorrect, sorry')
$('#submit-key').css('background-color', 'red')
$('#submit-key').prop('disabled', true)
$("#incorrect-key").slideDown();
$("#answer-input").addClass("wrong");
$("#answer-input").removeClass("correct");
setTimeout(function() {
$("#answer-input").removeClass("wrong");
}, 3000);
}
else if (data == 1){ // Challenge Solved
$('#submit-key').text('Correct!')
$('#submit-key').css('background-color', 'green')
$('#submit-key').prop('disabled', true)
$('#chal-window .chal-solves').text( (parseInt($('#chal-window .chal-solves').text().split(" ")[0]) + 1 + " solves") )
$("#correct-key").slideDown();
$('.chal-solves').text((parseInt($('.chal-solves').text().split(" ")[0]) + 1 + " Solves") )
$("#answer-input").val("");
$("#answer-input").removeClass("wrong");
$("#answer-input").addClass("correct");
}
else if (data == 2){ // Challenge already solved
$('#submit-key').text('You already solved this')
$('#submit-key').prop('disabled', true)
$("#already-solved").slideDown();
$("#answer-input").addClass("correct");
}
else if (data == 3){ // Keys per minute too high
$('#submit-key').text("You're submitting keys too fast. Slow down.")
$('#submit-key').css('background-color', '#e18728')
$('#submit-key').prop('disabled', true)
$("#too-fast").slideDown();
$("#answer-input").addClass("wrong");
setTimeout(function() {
$("#answer-input").removeClass("wrong");
}, 3000);
}
else if (data == 4){ // too many incorrect solves
$('#submit-key').text('Too many attempts.')
$('#submit-key').css('background-color', 'red')
$('#submit-key').prop('disabled', true)
}
marktoomanyattempts()
marksolves()
updatesolves()
setTimeout(function(){
$('#submit-key').text('Submit')
$('#submit-key').prop('disabled', false)
$('#submit-key').css('background-color', '#007095')
$('.alert').slideUp();
$('#submit-key').removeClass("disabled-button");
$('#submit-key').prop('disabled', false);
}, 3000);
})
}
@ -137,26 +125,13 @@ function marksolves() {
$.get('/solves', function (data) {
solves = $.parseJSON(JSON.stringify(data));
for (var i = solves['solves'].length - 1; i >= 0; i--) {
id = solves['solves'][i].chalid
$('#challenges button[value="' + id + '"]').addClass('secondary')
$('#challenges button[value="' + id + '"]').css('opacity', '0.3')
};
if (window.location.hash.length > 0){
loadchalbyname(window.location.hash.substring(1))
}
});
}
function marktoomanyattempts() {
$.get('/maxattempts', function (data) {
maxattempts = $.parseJSON(JSON.stringify(data));
for (var i = maxattempts['maxattempts'].length - 1; i >= 0; i--) {
id = maxattempts['maxattempts'][i].chalid
$('#challenges button[value="' + id + '"]').addClass('secondary')
$('#challenges button[value="' + id + '"]').css('background-color', '#FF9999')
id = solves['solves'][i].chalid;
$('button[value="' + id + '"]').removeClass('theme-background');
$('button[value="' + id + '"]').addClass('solved-challenge');
};
if (window.location.hash.length > 0){
loadchalbyname(window.location.hash.substring(1))
$("#chal-window").modal("show");
}
});
}
@ -166,7 +141,7 @@ function updatesolves(){
solves = $.parseJSON(JSON.stringify(data));
chals = Object.keys(solves);
for (var i = 0; i < chals.length; i++) {
for (var i = 0; i < chals.length; i++) {
obj = $.grep(challenges['game'], function (e) {
return e.name == chals[i];
})[0]
@ -196,39 +171,64 @@ function loadchals() {
categories = [];
challenges = $.parseJSON(JSON.stringify(data));
$('#challenges-board').html("");
for (var i = challenges['game'].length - 1; i >= 0; i--) {
challenges['game'][i].solves = 0
if ($.inArray(challenges['game'][i].category, categories) == -1) {
categories.push(challenges['game'][i].category)
$('#challenges').append($('<tr id="' + challenges['game'][i].category.replace(/ /g,"-").hashCode() + '"><td class="large-2"><h4>' + challenges['game'][i].category + '</h4></td></tr>'))
var category = challenges['game'][i].category;
categories.push(category);
var categoryid = category.replace(/ /g,"-").hashCode();
var categoryrow = $('<div id="{0}-row" class="row"><div class="category-header col-md-2"></div><div class="category-challenges col-md-9"><div class="row"></div></div></div>'.format(categoryid));
categoryrow.find(".category-header").append($("<h2>"+ category +"</h2>"));
$('#challenges-board').append(categoryrow);
}
};
for (var i = 0; i <= challenges['game'].length - 1; i++) {
var chal = challenges['game'][i]
var chal_button = $('<button class="chal-button" value="{0}"><p>{1}</p><span>{2}</span></button>'.format(chal.id, chal.name, chal.value))
$('#' + challenges['game'][i].category.replace(/ /g,"-").hashCode()).append(chal_button);
};
updatesolves()
marktoomanyattempts()
marksolves()
chalinfo = challenges['game'][i];
challenge = chalinfo.category.replace(/ /g,"-").hashCode();
var chalid = chalinfo.name.replace(/ /g,"-").hashCode();
var catid = chalinfo.category.replace(/ /g,"-").hashCode();
var chalwrap = $("<div id='{0}' class='challenge-wrapper col-md-2'></div>".format(chalid));
var chalbutton = $("<button class='challenge-button trigger theme-background hide-text' value='{0}' data-toggle='modal' data-target='#chal-window'></div>".format(chalinfo.id));
var chalheader = $("<h5>{0}</h5>".format(chalinfo.name));
var chalscore = $("<span>{0}</span>".format(chalinfo.value));
chalbutton.append(chalheader);
chalbutton.append(chalscore);
chalwrap.append(chalbutton);
$('#challenges button').click(function (e) {
$("#"+ catid +"-row").find(".category-challenges > .row").append(chalwrap);
};
updatesolves();
marksolves();
$('.challenge-button').click(function (e) {
loadchal(this.value);
});
});
}
$('#submit-key').click(function (e) {
submitkey($('#chal-id').val(), $('#answer').val(), $('#nonce').val())
submitkey($('#chal-id').val(), $('#answer-input').val(), $('#nonce').val())
});
$('.chal-solves').click(function (e) {
getsolves($('#chal-id').val())
});
$('#chal-window').on('hide.bs.modal', function (event) {
$("#answer-input").removeClass("wrong");
$("#answer-input").removeClass("correct");
$("#incorrect-key").slideUp();
$("#correct-key").slideUp();
$("#already-solved").slideUp();
$("#too-fast").slideUp();
});
// $.distint(array)
// Unique elements in array
$.extend({
@ -240,6 +240,7 @@ $.extend({
return result;
}
});
function colorhash (x) {
color = ""
for (var i = 20; i <= 60; i+=20){
@ -250,35 +251,17 @@ function colorhash (x) {
return "#" + color.substring(0, 6)
}
$(document).on('close', '[data-reveal]', function () {
window.location.hash = ""
});
// function solves_graph() {
// $.get('/graphs/solves', function(data){
// solves = $.parseJSON(JSON.stringify(data));
// chals = []
// counts = []
// colors = []
// i = 1
// $.each(solves, function(key, value){
// chals.push(key)
// counts.push(value)
// colors.push(colorhash(i++))
// });
// });
// }
function update(){
$('#challenges').empty()
loadchals()
solves_graph()
}
$(function() {
loadchals()
// solves_graph()
loadchals();
});
$('.nav-tabs a').click(function (e) {
e.preventDefault()
$(this).tab('show')
})
setInterval(update, 300000);

45
CTFd/static/js/input.js Normal file
View File

@ -0,0 +1,45 @@
(function() {
// trim polyfill : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
if (!String.prototype.trim) {
(function() {
// Make sure we trim BOM and NBSP
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
String.prototype.trim = function() {
return this.replace(rtrim, '');
};
})();
}
[].slice.call( document.querySelectorAll( 'input.input-field' ) ).forEach( function( inputEl ) {
// in case the input is already filled..
if( inputEl.value.trim() !== '' ) {
classie.add( inputEl.parentNode, 'input--filled' );
classie.add( inputEl.nextElementSibling, 'input--hide' );
$label = $(inputEl).siblings(".input-label");
$label.removeClass("input--hide");
$label.css({
"transform": "translate3d(0, 0, 0)"
});
}
} );
})();
$(".input-field").bind({
focus: function() {
$(this).parent().addClass('input--filled' );
$label = $(this).siblings(".input-label");
//$label.addClass('input--hide' );
$label.css({
"transform": "translate3d(0, 10%, 0)"
});
},
blur: function() {
if ($(this).val() === '') {
$(this).parent().removeClass('input--filled' );
$label = $(this).siblings(".input-label");
$label.removeClass('input--hide' );
$label.css({
"transform": "translate3d(0, 150%, 0)"
});
}
}
});

View File

@ -79,7 +79,7 @@ function scoregraph () {
team_scores.unshift(teams[i])
// team_scores.push( team_scores[team_scores.length-1] )
xs_data[teams[i]] = "x"+i
column_data.push(times)
column_data.push(team_scores)
@ -99,11 +99,11 @@ function scoregraph () {
x : {
tick: {
count: 10,
format: function (x) {
format: function (x) {
return moment(x*1000).local().format('LLL');
}
},
},
y:{
label: {

View File

@ -1,6 +1,6 @@
function teamid (){
loc = window.location.pathname
return parseInt(loc.substring(loc.lastIndexOf('/')+1, loc.length));
return loc.substring(loc.lastIndexOf('/')+1, loc.length);
}
function colorhash (x) {
@ -29,8 +29,6 @@ function scoregraph () {
solves = $.parseJSON(JSON.stringify(data));
solves = solves['solves']
console.log(solves)
if (solves.length == 0)
return
@ -46,8 +44,6 @@ function scoregraph () {
scores.unshift('data1')
// scores.push( scores[scores.length-1] )
console.log(scores)
var chart = c3.generate({
bindto: "#score-graph",
data: {
@ -70,11 +66,11 @@ function scoregraph () {
axis : {
x : {
tick: {
format: function (x) {
format: function (x) {
return moment(x).local().format('M/D h:mm:ss');
}
},
},
y:{
label: {

View File

@ -2,56 +2,57 @@
<html>
<head>
<title></title>
<title>Admin Panel</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="/static/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="/static/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/normalize.min.css" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/foundation.min.css" />
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/main-style.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<link href='//fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
<link href='//fonts.googleapis.com/css?family=Raleway:500' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/styles/railscasts.min.css">
<link rel="stylesheet" type="text/css" href="/static/admin/css/style.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js"></script>
{% block stylesheets %} {% endblock %}
</head>
<body>
<nav class="top-bar" data-topbar>
<ul class="title-area">
<li class="name">
<h1><a href="/">CTF</a></h1>
</li>
<li class="toggle-topbar menu-icon"><a href="#">Menu</a>
</li>
</ul>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/" class="navbar-brand">CTF</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav navbar-nav-right">
<li><a href="/admin/graphs">Graphs</a></li>
<li><a href="/admin/pages">Pages</a></li>
<li><a href="/admin/teams">Teams</a></li>
<li><a href="/admin/scoreboard">Scoreboard</a></li>
<li><a href="/admin/chals">Challenges</a></li>
<li><a href="/admin/statistics">Statistics</a></li>
<li><a href="/admin/config">Config</a></li>
</ul>
</div>
</div>
</div>
<section class="top-bar-section">
<!-- Right Nav Section -->
<ul class="right">
</li>
</ul>
<!-- Left Nav Section -->
<ul class="left">
<li><a href="/admin/graphs">Graphs</a></li>
<li><a href="/admin/pages">Pages</a></li>
<li><a href="/admin/teams">Teams</a></li>
<li><a href="/admin/scoreboard">Scoreboard</a></li>
<li><a href="/admin/chals">Challenges</a></li>
<li><a href="/admin/statistics">Statistics</a></li>
<li><a href="/admin/config">Config</a></li>
</ul>
</section>
</nav>
{% block content %} {% endblock %}
<div class="container">
{% block content %} {% endblock %}
</div>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/modernizr.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation/foundation.topbar.min.js"></script>
<script>
$(document).foundation();
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
{% block scripts %} {% endblock %}
</body>

View File

@ -1,141 +1,283 @@
{% extends "admin/base.html" %}
{% block stylesheets %}
<style>
.btn-primary { background-color: #337ab7; }
.btn-danger { background-color: #d9534f; }
.col-md-4 { margin-bottom: 15px; }
.key-remove-button { margin-top: 10px; }
.delete-tag { color: white; margin-left: 3px; cursor: pointer; }
</style>
{% endblock %}
{% block content %}
<div id="email-user" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
</div>
</div>
</div>
</div>
<input type="hidden" value="{{ nonce }}" id="nonce">
<div id="create-challenge" class="reveal-modal" data-reveal>
<h3>New Challenge</h3>
<form method="POST" action="/admin/chal/new" enctype="multipart/form-data">
<input type='text' name='name' placeholder='Name'><br/>
<input type='text' name='category' placeholder='Category'><br/>
<ul id="new-desc-edit" class="tabs" data-tab>
<li class="tab-title active"><a href="#new-desc-write" style="padding: 0 2rem;">Write</a></li>
<li class="tab-title"><a href="#new-desc-preview" style="padding: 0 2rem;">Preview</a></li>
</ul>
<div class="tabs-content">
<div class="content active" id="new-desc-write">
<textarea id="new-desc-editor" class="new-chal-desc" name='desc' placeholder='Description' rows="10"></textarea><br>
<div id="create-challenge" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3>New Challenge</h3>
</div>
<div class="content" id="new-desc-preview">
<div class="modal-body">
<form method="POST" action="/admin/chal/new" enctype="multipart/form-data">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" name="name" placeholder="Enter challenge name">
</div>
<div class="form-group">
<label for="category">Category</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 role="presentation" class="active"><a href="#new-desc-write" aria-controls="home" role="tab" data-toggle="tab">Write</a></li>
<li role="presentation"><a 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:</label>
<textarea id="new-desc-editor" class="form-control" name="desc" rows="10"></textarea>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="new-desc-preview">
</div>
</div>
<div class="form-group">
<label for="value">Value</label>
<input type="number" class="form-control" name="value" placeholder="Enter value">
</div>
<div class="form-group" style="height:75px">
<div class="col-md-9" style="padding-left:0px">
<label for="key">Key</label>
<input type="text" class="form-control" name="key" placeholder="Enter key">
</div>
<div class="col-md-3" style="margin-top:30px;padding-right:0px">
<div class="radio-inline">
<input type="radio" name="key_type[0]" value="0" checked>
Static
</div>
<div class="radio-inline">
<input type="radio" name="key_type[0]" value="1">
Regex
</div>
</div>
</div>
<div class="form-group">
<label for="exampleInputFile">Upload challenge files</label>
<input type="file" name="files[]" multiple="multiple">
</div>
<div style="text-align:center">
<button class="btn btn-theme btn-outlined create-challenge" type="submit">Create</button>
</div>
</form>
</div>
</div>
<input type='number' name='value' placeholder='Value'><br/>
<input type='text' name='key' placeholder='Key'><br/>
<input type="radio" name="key_type[0]" value="0" checked="checked">Static
<input type="radio" name="key_type[0]" value="1">Regex
<br/>
<input type="file" name="files[]" multiple="multiple">
<button type='submit'>Create</button>
<a class="close-reveal-modal">&#215;</a>
</form>
</div>
<div id="delete-chal" class="reveal-modal" data-reveal>
<h2 class="text-center">Delete Challenge</h2>
<form method="POST" action="/admin/chal/delete">
<input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id" class="chal-id">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete this challenge?</p>
<p>Solves, wrong keys, files, tags will all be deleted.</p>
<button type="button" class="button alert radius" onclick="$('#delete-chal').foundation('reveal', 'close');">No</button>
<button type="submit" id="delete-user" class="button success radius">Yes</button>
</div>
</form>
<a class="close-reveal-modal">&#215;</a>
</div>
<div id="update-keys" class="reveal-modal" data-reveal>
<form method="POST" action="/admin/keys">
<h3>Keys</h3>
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="keys-chal" name='chal' type='hidden'>
<div id="current-keys"></div>
<a href="#" id="create-key" class="secondary button">New Key</a>
<a href="#" id="submit-keys" class="button">Update</a>
<a class="close-reveal-modal">&#215;</a>
</form>
</div>
<div id="update-files" class="reveal-modal" data-reveal>
<form method="POST" action="/admin/files" enctype="multipart/form-data">
<h3>Files</h3>
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="files-chal" name='chal' type='hidden'>
<div id="current-files"></div>
<input type="hidden" name="method" value="upload">
<input type="file" name="files[]" multiple="multiple">
<button type='submit'>Upload</button>
<a class="close-reveal-modal">&#215;</a>
</form>
</div>
<div id="update-tags" class="reveal-modal" data-reveal>
<h3>Tags</h3>
<input type="text" class="tag-insert" maxlength="80" placeholder="Type tag and press Enter">
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="tags-chal" name='chal' type='hidden'>
<div id="current-tags">
</div>
<br/>
<div id="chal-tags">
</div>
<br/>
<a href="#" id="submit-tags" class="button">Update</a>
<a class="close-reveal-modal">&#215;</a>
</div>
<div id="update-challenge" class="reveal-modal" data-reveal>
<form method="POST" action="/admin/chal/update">
<h3 class="chal-title text-center"></h3>
<input name='nonce' type='hidden' value="{{ nonce }}">
Name: <input class="chal-name" type='text' name='name' placeholder='Name'><br>
Category: <input class="chal-category" type="text" name="category" placeholder="Category"><br>
Description:
<ul id="desc-edit" class="tabs" data-tab>
<li class="tab-title active"><a href="#desc-write" style="padding: 0 2rem;">Write</a></li>
<li class="tab-title"><a href="#desc-preview" style="padding: 0 2rem;">Preview</a></li>
</ul>
<div class="tabs-content">
<div class="content active" id="desc-write">
<textarea id="desc-editor" class="chal-desc" name='desc' placeholder='Description' rows="10"></textarea><br>
<div id="update-challenge" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="chal-title text-center"></h3>
</div>
<div class="content" id="desc-preview">
<div class="modal-body">
<form method="POST" action="/admin/chal/update">
<input name='nonce' type='hidden' value="{{ nonce }}">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control chal-name" name="name" placeholder="Enter challenge name">
</div>
<div class="form-group">
<label for="category">Category</label>
<input type="text" class="form-control chal-category" name="category" placeholder="Enter challenge category">
</div>
<ul class="nav nav-tabs" role="tablist" id="desc-edit">
<li role="presentation" class="active"><a href="#desc-write" aria-controls="home" role="tab" data-toggle="tab">Write</a></li>
<li role="presentation"><a href="#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="desc-write">
<div class="form-group">
<label for="message-text" class="control-label">Message:</label>
<textarea id="desc-editor" class="form-control chal-desc" name="desc" rows="10"></textarea>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="desc-preview">
</div>
</div>
<div class="form-group">
<label for="value">Value</label>
<input type="number" class="form-control chal-value" name="value" placeholder="Enter value">
</div>
<input class="chal-id" type='hidden' name='id' placeholder='ID'>
<div class="form-group">
<a href="#" data-toggle="modal" data-target="#update-tags" class="btn btn-primary">Tags</a>
<a href="#" data-toggle="modal" data-target="#update-files" class="btn btn-primary">Files</a>
<a href="#" data-toggle="modal" data-target="#update-keys" class="btn btn-primary">Keys</a>
<a href="#" data-toggle="modal" data-target="#delete-chal" class="btn btn-danger">Delete</a>
</div>
<div style="text-align:center">
<button class="btn btn-theme btn-outlined create-challenge" type="submit">Update</button>
</div>
</form>
</div>
</div>
Value: <input class="chal-value" type='number' name='value' placeholder='Value'><br>
<input class="chal-id" type='hidden' name='id' placeholder='ID'>
<a href="#" data-reveal-id="update-tags" class="secondary button">Tags</a>
<a href="#" data-reveal-id="update-files" class="secondary button">Files</a>
<a href="#" data-reveal-id="update-keys" class="secondary button">Keys</a>
<a href="#" data-reveal-id="delete-chal" class="secondary alert button">Delete</a>
<button type='submit'>Update</button>
<a class="close-reveal-modal">&#215;</a>
</form>
</div>
</div>
<div>
<div id="delete-chal" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Delete Challenge</h3>
</div>
<div class="modal-body">
<form method="POST" action="/admin/chal/delete">
<input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id" class="chal-id">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete this challenge?</p>
<p>Solves, wrong keys, files, tags will all be deleted.</p>
<a onclick="$('#delete-chal').modal('hide')" class="btn btn-primary">No</a>
<button class="btn btn-danger" id="delete-user" type="submit">Delete</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="update-keys" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Keys</h3>
</div>
<div class="modal-body">
<form method="POST" action="/admin/keys" style="text-align:center">
<a href="#" id="create-key" class="btn btn-primary" style="margin-bottom:15px;">New Key</a>
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="keys-chal" name='chal' type='hidden'>
<div id="current-keys" class="row"></div>
<div class="row">
<button id="submit-keys" class="btn btn-theme btn-outlined">Update</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="update-files" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Files</h3>
</div>
<div class="modal-body">
<form method="POST" action="/admin/files/" enctype="multipart/form-data">
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="files-chal" name='chal' type='hidden'>
<input name='method' type='hidden' value='upload'>
<div id="current-files"></div>
<input type="hidden" name="method" value="upload">
<input type="file" name="files[]" multiple="multiple">
<div class="row" style="text-align:center;margin-top:20px">
<button class="btn btn-theme btn-outlined" type="submit">Update</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="update-tags" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Tags</h3>
</div>
<div class="modal-body">
<div class="form-group">
<label for="tag-insert">Value</label>
<input max-length="80" type="text" class="form-control tag-insert" name="tag-insert" placeholder="Type tag and press Enter">
</div>
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="tags-chal" name='chal' type='hidden'>
<div id="current-tags">
</div>
<br/>
<div id="chal-tags">
</div>
<div class="row" style="text-align:center;margin-top:20px">
<button class="btn btn-theme btn-outlined" id="submit-tags">Update</button>
</div>
</div>
</div>
</div>
</div>
<div id="email-user" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Tags</h3>
</div>
<div class="modal-body">
<input type="text" class="tag-insert" maxlength="80" placeholder="Type tag and press Enter">
<input name='nonce' type='hidden' value="{{ nonce }}">
<input id="tags-chal" name='chal' type='hidden'>
<div id="current-tags">
</div>
<br/>
<div id="chal-tags">
</div>
<br/>
<a href="#" id="submit-tags" class="button">Update</a>
<a class="close-reveal-modal">&#215;</a>
</div>
</div>
</div>
</div>
<div style="text-align:center">
<h1 class="text-center">Challenges</h1>
<button class="btn btn-theme btn-outlined create-challenge">New Challenge</button>
<div>
<table id='challenges'>
</table>
<button style="width:100%;" class="radius create-challenge">New Challenge</button>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="/static/admin/js/multi-modal.js"></script>
<script src="/static/admin/js/chalboard.js"></script>
{% endblock %}

View File

@ -2,58 +2,67 @@
{% block content %}
<div class="row">
<br>
<h1>Config</h1>
<form method="POST">
<input name='nonce' type='hidden' value="{{ nonce }}">
<div class="col-md-4 col-md-offset-4">
<form method="POST">
<input name='nonce' type='hidden' value="{{ nonce }}">
<div class="row">
<label for="start">CTF Name:</label>
<input id='ctf_name' name='ctf_name' type='text' placeholder="CTF Name" {% if ctf_name is defined and ctf_name != None %}value="{{ ctf_name }}"{% endif %}>
</div>
<div class="form-group">
<label for="ctf_name">CTF Name:</label>
<input class="form-control" id='ctf_name' name='ctf_name' type='text' placeholder="CTF Name" {% if ctf_name is defined and ctf_name != None %}value="{{ ctf_name }}"{% endif %}>
</div>
<div class="row">
<label for="max_tries">Maximum Attempts Per Challenge (0 to disable):</label>
<input id='max_tries' name='max_tries' type='text' placeholder="0" {% if max_tries is defined and max_tries != None %}value="{{ max_tries }}"{% endif %}>
</div>
<div class="form-group">
<label for="max_tries">Maximum Attempts Per Challenge (0 to disable):</label>
<input class="form-control" id='max_tries' name='max_tries' type='text' placeholder="0" {% if max_tries is defined and max_tries != None %}value="{{ max_tries }}"{% endif %}>
</div>
<div class="row">
<label for="start">Mailgun API Key:</label>
<input id='mg_api_key' name='mg_api_key' type='text' placeholder="Mailgun API Key" {% if mg_api_key is defined and mg_api_key != None %}value="{{ mg_api_key }}"{% endif %}>
</div>
<div class="form-group">
<label for="start">Mailgun API Key:</label>
<input class="form-control" id='mg_api_key' name='mg_api_key' type='text' placeholder="Mailgun API Key" {% if mg_api_key is defined and mg_api_key != None %}value="{{ mg_api_key }}"{% endif %}>
</div>
<div class="row">
<label for="start">Start Date:</label>
<input id='start' name='start' type='text' placeholder="Start Date (UTC timestamp)" {% if start is defined and start != None %}value="{{ start }}"{% endif %}>
</div>
<div class="form-group">
<label for="start">Start Date:</label>
<input class="form-control" id='start' name='start' type='text' placeholder="Start Date (UTC timestamp)" {% if start is defined and start != None %}value="{{ start }}"{% endif %}>
</div>
<div class="row">
<label for="end">End Date:</label>
<input id='end' name='end' type='text' placeholder="End Date (UTC timestamp)" {% if end is defined and end != None %}value="{{ end }}"{% endif %}>
</div>
<div class="form-group">
<label for="end">End Date:</label>
<input class="form-control" id='end' name='end' type='text' placeholder="End Date (UTC timestamp)" {% if end is defined and end != None %}value="{{ end }}"{% endif %}>
</div>
<div class="row">
<input id="view_after_ctf" name="view_after_ctf" type="checkbox" {% if view_after_ctf %}checked{% endif %}>
<label for="end">Allow challenges to be viewed after CTF end</label>
</div>
<div class="checkbox">
<label>
<input id="view_after_ctf" name="view_after_ctf" type="checkbox" {% if view_after_ctf %}checked{% endif %}>
Allow challenges to be viewed after CTF end
</label>
</div>
<div class="row">
<input id="view_challenges_unregistered" name="view_challenges_unregistered" type="checkbox" {% if view_challenges_unregistered %}checked{% endif %}>
<label for="view_challenges_unregistered">Unregistered users can view challenges</label>
</div>
<div class="checkbox">
<label>
<input id="view_challenges_unregistered" name="view_challenges_unregistered" type="checkbox" {% if view_challenges_unregistered %}checked{% endif %}>
Unregistered users can view challenges
</label>
</div>
<div class="row">
<input id="prevent_registration" name="prevent_registration" type="checkbox" {% if prevent_registration %}checked{% endif %}>
<label for="prevent_registration">Prevent public registration</label>
</div>
<div class="checkbox">
<label>
<input id="prevent_registration" name="prevent_registration" type="checkbox" {% if prevent_registration %}checked{% endif %}>
Prevent public registration
</label>
</div>
<div class="row">
<input id="prevent_name_change" name="prevent_name_change" type="checkbox" {% if prevent_name_change %}checked{% endif %}>
<label for="prevent_name_change">Prevent team name changes</label>
</div>
<div class="checkbox">
<label>
<input id="prevent_name_change" name="prevent_name_change" type="checkbox" {% if prevent_name_change %}checked{% endif %}>
Prevent team name changes
</label>
</div>
<button class="radius" type='submit'>Update</button>
</form>
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-primary btn-theme btn-outlined pull-right">Update</button>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,7 +1,14 @@
{% extends "admin/base.html" %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.11.0/theme/elegant.min.css">
<style>
.row-fluid { margin: 25px; padding-bottom: 25px; }
</style>
{% endblock %}
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.css">
<div class="row">
<div class="row">
{% for error in errors %}
@ -13,25 +20,36 @@
</div>
{% endfor %}
</div>
<form id="page-edit" method="POST">
<br>
<strong>Route: </strong><input name='nonce' type='hidden' value="{{ nonce }}">
<input class="radius" id="route" type="text" name="route" value="{% if page is defined %}{{ page.route }}{% endif %}" placeholder="Route">
<strong>HTML: </strong><textarea id="admin-pages-editor" name="html">{% if page is defined %}{{ page.html }}{% endif %}</textarea><br>
<button class="radius" type='submit'>Create</button>
<div class="row-fluid">
<div class="col-md-12">
<strong>Route: </strong><input name='nonce' type='hidden' value="{{ nonce }}">
<input class="radius" id="route" type="text" name="route" value="{% if page is defined %}{{ page.route }}{% endif %}" placeholder="Route">
</div>
</div>
<div class="row-fluid">
<div class="col-md-12">
<textarea id="admin-pages-editor" name="html">{% if page is defined %}{{ page.html }}{% endif %}</textarea><br>
<button class="btn btn-theme btn-outlined create-challenge pull-right">Create</button>
</div>
</div>
</form>
</div>
{% endblock %}
{% block scripts %}
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.2.0/mode/xml/xml.min.js"></script>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("admin-pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "text/html"
lineNumbers: true,
lineWrapping: true,
mode: "xml",
htmlMode: true,
theme: 'elegant'
});
$('#page-edit').submit(function (e){
$(this).attr('action', '/admin/pages/'+$('#route').val());
});

View File

@ -2,14 +2,25 @@
{% block content %}
<div class="row">
<div id="solves-graph"></div>
<div id="keys-pie-graph"></div>
<div id="categories-pie-graph"></div>
<div class="col-md-6 col-md-offset-1">
<div id="solves-graph"></div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div id="keys-pie-graph"></div>
</div>
<div class="col-md-6">
<div id="categories-pie-graph"></div>
</div>
</div>
{% endblock %}
{% block scripts %}
<style>
.row {
text-align: center;
}
#solves-graph{
margin-left: -50px;
}
@ -97,7 +108,7 @@
});
});
}
function keys_percentage_graph(){
// Solves and Fails pie chart
$.get('/admin/fails/all', function(data){
@ -124,7 +135,7 @@
});
});
}
function category_breakdown_graph(){
$.get('/admin/graphs/categories', function(data){
res = $.parseJSON(JSON.stringify(data));
@ -163,6 +174,6 @@
});
setInterval(update, 300000);
</script>
{% endblock %}

View File

@ -1,29 +1,84 @@
{% extends "base.html" %}
{% block stylesheets %}
<link rel="stylesheet" href="/static/css/input.css">
<style>
.input {
width: 100%;
}
#login-container {
padding-left: 60px;
padding-right: 60px;
}
#submit {
position: relative;
right: -30px;
}
.done-row {
padding-top: 15px;
margin: 0px;
}
</style>
{% endblock %}
{% block content %}
<div class="row">
<h1>Login</h1>
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
</div>
</div>
{% endfor %}
<div class="jumbotron home">
<div class="container">
<h1>Login</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" />
<label class="input-label" for="name-input">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6">
<a class="pull-left align-text-to-button" href="/reset_password">Forgot your password?</a>
</div>
<div class="col-md-6">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
</form>
</div>
</div>
<form method="POST">
<input class="radius" type='text' name='name' placeholder='Name'><br/>
<input class="radius" type='password' name='password' placeholder='Password'><br/>
<p><a href="/reset_password">Forgot your password?</a></p>
<button class="radius" type='submit'>Login</button>
</form>
</div>
{% endblock %}
{% block scripts %}
{% endblock %}
<script src="//cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<script src="/static/js/input.js"></script>
{% endblock %}

View File

@ -1,30 +1,46 @@
{% extends "admin/base.html" %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.11.0/theme/elegant.min.css">
{% endblock %}
{% block content %}
<div class="row">
<br>
<div id="confirm" class="reveal-modal" data-reveal>
<h2 class="text-center">Delete Page</h2>
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-route-name"></strong>?</p>
<button type="button" class="button alert radius" onclick="$('#confirm').foundation('reveal', 'close');">No</button>
<button type="button" id="delete-route" class="button success radius">Yes</button>
<div id="confirm" class="modal fade" tabindex="-1" data-width="760">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Delete Page</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-route-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="delete-route" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</form>
<a class="close-reveal-modal">&#215;</a>
</div>
</div>
<div class="small-6 columns">
<div class="col-md-9">
<h3>CSS editor <a onclick="save_css()"><i class="fa fa-floppy-o"></i></a></h3>
<div style="height: 500px;" id="admin-css-editor" name="css">{{ css }}</div>
<textarea id="pages-editor" name="html">{{ css }}</textarea>
</div>
<div class="small-6 columns">
<div class="col-md-3">
<h3>HTML Pages <a href="/admin/pages?mode=create"><i class="fa fa-plus"></i></a></h3>
<table id="pages">
<table id="pages" class="table table-striped">
<thead>
<tr>
<td><b>Route</b></td>
@ -45,10 +61,17 @@
{% endblock %}
{% block scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-github.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-css.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.2.0/mode/xml/xml.min.js"></script>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "xml",
htmlMode: true,
theme: 'elegant'
});
$('#delete-route').click(function(e){
e.preventDefault();
var route = $('#confirm input[name="route"]').val()
@ -65,7 +88,7 @@ function load_confirm_modal(route){
modal.find('input[name=route]').val(route)
modal.find('#confirm-route-name').text(route)
$('#confirm form').attr('action', '/admin/page/'+route+'/delete');
$('#confirm').foundation('reveal', 'open');
$('#confirm').modal();
}
function save_css(){
@ -82,9 +105,5 @@ $('.fa-times').click(function(){
load_confirm_modal(name)
});
var editor = ace.edit("admin-css-editor");
editor.setTheme("ace/theme/github");
editor.getSession().setMode("ace/mode/css");
</script>
{% endblock %}

View File

@ -3,7 +3,7 @@
{% block content %}
<div class="row">
<br>
<table id="scoreboard">
<table id="scoreboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>Place</b></td>

View File

@ -2,7 +2,7 @@
{% block content %}
<div class="row">
<div class="row" style="text-align:center">
<h1>Statistics</h1>
<h3><b>{{ team_count }}</b> teams registered</h3>

View File

@ -1,79 +1,103 @@
{% extends "admin/base.html" %}
{% block content %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
<style>
td { text-align:center; }
.checkbox { margin: 0px !important; }
input[type="checkbox"] { margin: 0px !important; position: relative; top: 5px; }
</style>
{% endblock %}
{% block content %}
<div class="row">
<br>
<div id="confirm" class="reveal-modal" data-reveal>
<h2 class="text-center">Delete User</h2>
<form method="POST">
<input type="hidden" name="id">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-team-name"></strong>?</p>
<button type="button" class="button alert radius" onclick="$('#confirm').foundation('reveal', 'close');">No</button>
<button type="button" id="delete-user" class="button success radius">Yes</button>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Delete User</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-team-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="delete-user" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</form>
<a class="close-reveal-modal">&#215;</a>
</div>
</div>
<div id="email-user" class="reveal-modal" data-reveal>
<h2 class="text-center">Email User</h2>
<form method="POST">
<input type="hidden" name="id">
<input type="hidden" name="nonce" value="{{ nonce }}">
<textarea name="msg" placeholder="Enter your message here" rows="15"></textarea>
<div id="email-user-errors"></div>
<button type="button" id="send-user-email">Send Message</button>
</form>
<a class="close-reveal-modal">&#215;</a>
<div id="email-user" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Email User</h2>
</div>
<div class="modal-body">
<form method="POST">
<input type="hidden" name="id">
<input type="hidden" name="nonce" value="{{ nonce }}">
<textarea name="msg" placeholder="Enter your message here" rows="15"></textarea>
<div id="email-user-errors"></div>
<button type="button" id="send-user-email">Send Message</button>
</form>
</div>
</div>
</div>
</div>
<div id="user" class="reveal-modal" data-reveal>
<h2 class="text-center">Edit User</h2>
<form method="POST" action="/admin/teams/">
<div class="row">
<input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id">
<div class="large-12 columns">
<label>Team Name
<input type="text" name="name" placeholder="Enter new team name" />
</label>
<div id="user" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Edit User</h2>
</div>
<div class="large-12 columns">
<label>Email
<input type="text" name="email" placeholder="Enter new email" />
</label>
</div>
<div class="large-12 columns">
<label>Password
<input type="password" name="password" placeholder="Enter new password" />
</label>
</div>
<div class="large-12 columns">
<label>Website
<input type="text" name="website" placeholder="Enter Website" />
</label>
</div>
<div class="large-6 columns">
<label>Affiliation
<input type="text" name="affiliation" placeholder="Enter Affiliation" />
</label>
</div>
<div class="large-6 columns">
<label>Country
<input type="text" name="country" placeholder="Enter Country" />
</label>
</div>
<div id="results">
<div class="modal-body" style="padding:20px; height:525px;">
<form method="POST" action="/admin/teams/">
<input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">Team Name</label>
<input type="text" class="form-control" name="name" id="name" placeholder="Enter new team name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email" placeholder="Enter new email">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password" />
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="text" class="form-control" name="website" id="website" placeholder="Enter website">
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation" placeholder="Enter affiliation">
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<input type="text" class="form-control" name="country" id="country" placeholder="Enter country">
</div>
<div id="results">
</div>
<button id="update-user" type="submit" class="btn btn-theme btn-outlined pull-right">Update</button>
</form>
</div>
<button id="update-user" class="radius" type="submit">Update</button>
</div>
</form>
<a class="close-reveal-modal">&#215;</a>
</div>
</div>
<table id="teamsboard">
<table id="teamsboard" class="table table-striped">
<thead>
<tr>
<td width="10px" class="text-center"><b>ID</b>
@ -126,7 +150,7 @@
<div class="text-center">Page
<br>
{% for page in range(1, pages + 1) %}
<a href="/admin/teams/{{ page }}">{{ page }}</a>
<a href="/admin/teams/{{ page }}">{{ page }}</a>
{% endfor %}
<a href="">
</div>
@ -138,16 +162,15 @@
<script>
function load_update_modal(id, name, email, website, affiliation, country){
var modal_form = $('#user form');
modal_form.find('input[name=name]').val(name)
modal_form.find('input[name=id]').val(id)
modal_form.find('input[name=email]').val(email)
modal_form.find('input[name=website]').val(website)
modal_form.find('input[name=affiliation]').val(affiliation)
modal_form.find('input[name=country]').val(country)
console.log(modal_form);
$('#user form').attr('action', '/admin/team/'+id)
$('#user').foundation('reveal', 'open');
$('#user').modal("show");
}
$('#update-user').click(function(e){
@ -170,7 +193,7 @@ $('#update-user').click(function(e){
row.find('.team-affiliation').text( $.grep(user_data, function(e){ return e.name == 'affiliation'; })[0]['value'] );
row.find('.team-country').text( $.grep(user_data, function(e){ return e.name == 'country'; })[0]['value'] );
$('#user').foundation('reveal', 'close');
$('#user').modal();
}
else{
$('#results').append($('p').text( data['data'][i] ))
@ -195,7 +218,7 @@ $('#send-user-email').click(function(e){
var email_data = $('#email-user form').serializeArray();
$.post($('#email-user form').attr('action'), $('#email-user form').serialize(), function(data){
if (data == "1"){
$('#email-user').foundation('reveal', 'close');
$('#email-user').modal();
}
else{
$('#email-user-errors').append("<b>Failed to send email</b>");
@ -232,7 +255,7 @@ function load_confirm_modal(id, name){
modal.find('input[name=id]').val(id)
modal.find('#confirm-team-name').text(name)
$('#confirm form').attr('action', '/admin/team/'+id+'/delete');
$('#confirm').foundation('reveal', 'open');
$('#confirm').modal();
}
$('.fa-times').click(function(){
@ -248,7 +271,7 @@ function load_email_modal(id){
modal.find('input[name=id]').val(id)
$('#email-user-errors').empty()
$('#email-user form').attr('action', '/admin/team/'+id+'/mail');
$('#email-user').foundation('reveal', 'open');
$('#email-user').modal();
}
$('.fa-envelope').click(function(){

View File

@ -6,72 +6,67 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="/static/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="/static/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/normalize.min.css" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/css/foundation.min.css" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/main-style.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" />
<link href='//fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
<link href='//fonts.googleapis.com/css?family=Raleway:500' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.3/styles/railscasts.min.css">
<link rel="stylesheet" type="text/css" href="/static/css/style.css">
<link rel="stylesheet" type="text/css" href="/static/user.css">
{% block stylesheets %}{% endblock %}
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js"></script>
</head>
<body>
<nav class="top-bar" data-topbar>
<ul class="title-area">
<li class="name">
<h1><a href="/">{{ ctf_name() }}</a></h1>
</li>
<li class="toggle-topbar menu-icon"><a href="#">Menu</a></li>
</ul>
<section class="top-bar-section">
<!-- Right Nav Section -->
<ul class="right">
{% if username is defined %}
<li class="has-dropdown">
<a href="/team/{{ id }}">{{ username }} {% if admin %} (ADMIN) {% endif %}</a>
<ul class="dropdown">
{% if admin %}
<li><a href="/admin">Admin</a></li>
{% endif %}
<li><a href="/team/{{ id }}">Team</a></li>
<li><a href="/profile">Account</a></li>
<li><a href="/logout">Logout</a></li>
</ul>
</li>
{%else %}
<li class="has-form">
{% if can_register() %}
<li><a href="/register">Register</a></li>
{% endif %}
<li><a href="/login">Login</a></li>
{% endif %}
</li>
</ul>
<!-- Left Nav Section -->
<ul class="left">
{% for page in pages() %}
<li><a href="/{{ page.route }}">{{ page.route|title }}</a></li>
{% endfor %}
<li><a href="/teams">Teams</a></li>
<li><a href="/scoreboard">Scoreboard</a></li>
<li><a href="/challenges">Challenges</a></li>
</ul>
</section>
</nav>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/" class="navbar-brand">{{ ctf_name() }}</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav">
{% for page in pages() %}
<li><a href="/{{ page.route }}">{{ page.route|title }}</a></li>
{% endfor %}
<li><a href="/teams">Teams</a></li>
<li><a href="/scoreboard">Scoreboard</a></li>
<li><a href="/challenges">Challenges</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
{% if username is defined %}
{% if admin %}
<li><a href="/admin">Admin</a></li>
{% endif %}
<li><a href="/team/{{ id }}">Team</a></li>
<li><a href="/profile">Profile</a></li>
<li><a href="/logout">Logout</a></li>
{% else %}
{% if can_register() %}
<li><a href="/register">Register</a></li>
<li><a style="padding-left:0px;padding-right:0px;">|</a></li>
{% endif %}
<li><a href="/login">Login</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
{% block content %}
{% endblock %}
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/modernizr.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/foundation/foundation.topbar.min.js"></script>
<script>
$(document).foundation();
</script>
{% block scripts %}
{% endblock %}
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/foundation/5.4.7/js/vendor/modernizr.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
{% block scripts %}
{% endblock %}
</body>
</html>

View File

@ -1,53 +1,164 @@
{% extends "base.html" %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/jquery.isotope/2.2.0/isotope.pkgd.min.js">
<link rel="stylesheet" href="/static/css/input.css">
<style>
.hide-text { text-overflow: ellipsis; overflow: hidden; }
.dialog-inner {padding-bottom: 30px;}
.alert {display: none}
.category-header {text-align: center}
.challenge-wrapper {padding: 5px;}
.challenge-button {width: 100%}
.submit-row {padding-top: 0px; padding-right: 0px; padding-left: 0px;}
.disabled-button {background-color: #EEEEEE}
.file-button {text-decoration: none; color: #fff;}
.file-button:hover {text-decoration: none; color: #fff;}
.file-wrapper {padding: 20px; transition: all 0.5s ease; cursor: pointer; color: #fff; width: 100%; text-overflow: ellipsis; overflow: hidden;}
.file-button {cursor: pointer;}
.file-button-wrapper {padding: 0px 10px;}
.close-text {color: #ccc;position: relative;top: -25px;right: -15px;cursor: pointer;}
.chal-desc {padding-left: 30px; padding-right: 30px;}
.key-submit {padding-top: 14px; padding-right: 10px;}
.notification-row {padding-left: 10px;padding-right: 10px;}
.input {padding-right: 5px;}
.input-field:focus + .input-field,
.input--filled .input-field {
border-color: rgb(238, 238, 238);
}
.input-field:focus + .input-field,
.input--filled .correct {
border-color: rgb(223, 240, 216);
}
.input-field:focus + .input-field,
.input--filled .wrong {
border-color: rgb(255, 190, 190);
}
a, button {
color: #74716D;
text-decoration: none;
outline: none;
}
a:hover, a:focus {
color: #c94e50;
outline: none;
}
button {
padding: 1em 2em;
outline: none;
font-weight: 600;
border: none;
color: #fff;
background: #c94e50;
}
.content {
max-width: 1000px;
padding: 2em;
margin: 0 auto;
text-align: center;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.button-wrap {
padding: 2.5em 0 0;
font-size: 1.25em;
}
button.trigger {
background: #c94e50;
color: #fff;
border: none;
}
</style>
{% endblock %}
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
<div id="chal-solves-window" class="reveal-modal" data-reveal>
<h3>Solved By</h3>
<div class="scroll-wrap">
<table>
<thead>
<tr>
<td><b>Name</b>
</td>
<td><b>Date</b>
</td>
</tr>
</thead>
<tbody id="chal-solves-names">
</tbody>
</table>
<div class="jumbotron home">
<div class="container">
<h1>Challenges</h1>
</div>
</div>
<div class="container main-container">
<div id='challenges-board' class="row">
</div>
<a class="close-reveal-modal" data-reveal-id="chal-window">&#215;</a>
</div>
<div id="chal-window" class="reveal-modal" data-reveal>
<div class="row">
<h3 class='chal-name'></h3>
<h4 class="chal-value"></h4>
<p><i><a data-reveal-id="chal-solves-window" class="chal-solves"></a></i></p>
<p class="chal-desc"></p>
{% if ctftime %}
<input id="answer" type="text" placeholder="Key">
<input type="hidden" id="nonce" name="nonce" value={{ nonce }}>
<button id="submit-key">Submit</button>
{% endif %}
<input id="chal-id" type="hidden">
</div>
<a class="close-reveal-modal">&#215;</a>
</div>
<div class="modal fade" id="chal-window" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content content">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#challenge" aria-controls="challenge" role="tab">Challenge</a></li>
<li role="presentation"><a href="#solves" aria-controls="solves" class="chal-solves" role="tab"></a></li>
</ul>
<div class="modal-body">
<div role="tabpanel">
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="challenge">
<h3 class='chal-name'></h3>
<h4 class="chal-value"></h4>
<p class="chal-desc"></p>
<div class="chal-files file-row row">
</div>
<div>
<h1 class="text-center">Challenges</h1>
<br>
<div class="large-12 columns">
<table id='challenges'>
</table>
<div class="row submit-row">
<div class="col-md-9" style="padding-right:0px;padding-left:10px;">
<span class="input">
<input class="input-field" type="text" name="answer" id="answer-input" placeholder="Key" />
</span>
<input type="hidden" id="nonce" name="nonce" value={{ nonce }}>
<input id="chal-id" type="hidden">
</div>
<div class="col-md-3 key-submit">
<button type="submit" id="submit-key" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right" style="height:46.375px">Submit</button>
</div>
</div>
<div class="row notification-row">
<div id="incorrect-key" class="alert alert-danger alert-dismissable" role="alert">
<strong>Incorrect</strong>
</div>
<div id="correct-key" class="alert alert-success alert-dismissable" role="alert">
<strong>Correct</strong>
</div>
<div id="already-solved" class="alert alert-info alert-dismissable" role="alert">
<strong>You already solved this</strong>
</div>
<div id="too-fast" class="alert alert-warning alert-dismissable" role="alert">
<strong>You're submitting keys too fast. Slow down.</strong>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="solves">
<table class="table table-striped">
<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 id="solves-graph" style="width: 90%; height: 400px; margin: 0 auto"></div>
</div>
</div>
{% endblock %}
{% block scripts %}
@ -55,4 +166,13 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.9/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<script src="/static/js/chalboard.js"></script>
<script src="/static/js/input.js"></script>
<script>
$('[data-dialog-close]').click(function() {
$('.nav-tabs > li:nth-child(1)').addClass("active");
$('.nav-tabs > li:nth-child(2)').removeClass("active");
openDialog.toggle();
window.location.hash = ""
});
</script>
{% endblock %}

View File

@ -1,30 +1,73 @@
{% extends "base.html" %}
{% block stylesheets %}
<link rel="stylesheet" href="/static/css/input.css">
<style>
#login-container {
padding-left: 60px;
padding-right: 60px;
}
.done-row {
padding-top: 15px;
margin: 0px;
}
</style>
{% endblock %}
{% block content %}
<div class="row">
<h1>Login</h1>
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
</div>
</div>
{% endfor %}
<div class="jumbotron home">
<div class="container">
<h1>Login</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" />
<label class="input-label" for="name-input">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6" style="padding-left:0px">
<a class="pull-left align-text-to-button" href="/reset_password">Forgot your password?</a>
</div>
<div class="col-md-6">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
</form>
</div>
</div>
<form method="POST">
<input class="radius" type='text' name='name' placeholder='Name'><br/>
<input class="radius" type='password' name='password' placeholder='Password'><br/>
<p><a href="/reset_password">Forgot your password?</a></p>
<input type="hidden" name="nonce" value="{{nonce}}">
<button class="radius" type='submit'>Login</button>
</form>
</div>
{% endblock %}
{% block scripts %}
{% endblock %}
<script src="//cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<script src="/static/js/input.js"></script>
{% endblock %}

View File

@ -1,46 +1,133 @@
{% extends "base.html" %}
{% extends "base.html" %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
<link rel="stylesheet" href="/static/css/input.css">
<style>
hr {
margin-top: 0px;
padding-bottom: 10px;
}
.row {
margin-bottom: 10px;
}
</style>
{% endblock %}
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
<div class="row">
<br/>
{% for error in errors %}
<h1>{{ error }}</h1>
{% endfor %}
<form method="POST">
<span>Team Name</span>
<input class="radius" type="text" name="name" placeholder="Team Name" value="{{name}}" {% if prevent_name_change %}disabled{% endif %}>
<span>Email Address</span>
<input class="radius" type="text" name="email" placeholder="Email Address" value="{{email}}">
<br/>
<hr/>
<br/>
<span>Old Password</span>
<input class="radius" type="password" name="confirm" placeholder="Old Password">
<span>Password</span>
<input class="radius" type="password" name="password" placeholder="Password">
<br/>
<hr/>
<br/>
<span>Website</span>
<input class="radius" type="text" name="website" placeholder="Website" value="{% if website %}{{website}}{% endif %}">
<span>Affiliation</span>
<input class="radius" type="text" name="affiliation" placeholder="Affiliation" value="{% if affiliation %}{{affiliation}}{% endif %}">
<span>Country</span>
<input class="radius" type="text" name="country" placeholder="Country" value="{% if country %}{{country}}{% endif %}">
<input type="hidden" name="nonce" value="{{nonce}}">
<button class="radius">Update</button>
</form>
<div class="jumbotron home">
<div class="container">
<h1>Profile</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% if success %}
<div class="alert alert-success alert-dismissable submit-row" role="alert">
<strong>Success!</strong>
Your profile has been updated
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% else %}
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
{% endif %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" value="{{name}}"/>
<label class="input-label" for="name-input">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="email-input" value="{{email}}"/>
<label class="input-label" for="email-input">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="confirm" id="confirm-input" />
<label class="input-label" for="confirm-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="New Password">New Password</span>
</label>
</span>
</div>
</div>
<hr />
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="affiliation" id="affiliation-input" value="{% if affiliation %}{{affiliation}}{% endif %}" />
<label class="input-label" for="affiliation-input">
<span class="label-content" data-content="Affiliation">Affiliation</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="website" id="website-input" value="{% if website %}{{website}}{% endif %}" />
<label class="input-label" for="website-input">
<span class="label-content" data-content="Website">Website</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="country" id="country-input" value="{% if country %}{{country}}{% endif %}" />
<label class="input-label" for="country-input">
<span class="label-content" data-content="Country">Country</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="submit-row">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-primary btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.9/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<script src="/static/js/team.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<script src="/static/js/input.js"></script>
{% endblock %}

View File

@ -1,34 +1,73 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<h1>Register</h1>
{% block stylesheets %}
<link rel="stylesheet" href="/static/css/input.css">
{% endblock %}
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Register</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6 col-md-offset-6" style="margin-top:10px">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
</form>
</div>
</div>
{% endfor %}
</div>
<form method="POST">
<input type='text' class="radius" name='name' placeholder='Team Name' {% if name %}value="{{ name }}"{% endif %}><br/>
<input type='text' class="radius" name='email' placeholder='Email' {% if email %}value="{{ email }}"{% endif %}><br/>
<input type='password' class="radius" name='password' placeholder='Password' {% if password %}value="{{ password }}"{% endif %}><br/>
<button class="radius" type='submit'>Register</button>
</form>
</div>
{% endblock %}
{% block scripts %}
<script src="//cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<script src="/static/js/input.js"></script>
<script>
if (window.location.hash == "#frame"){
$('.top-bar').hide()
}
</script>
{% endblock %}
{% endblock %}

View File

@ -1,34 +1,60 @@
{% extends "base.html" %}
{% block stylesheets %}
<link rel="stylesheet" href="/static/css/input.css">
{% endblock %}
{% block content %}
<div class="row">
<h1>Reset Password</h1>
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
</div>
</div>
{% endfor %}
<div class="jumbotron home">
<div class="container">
<h1>Reset Password</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
{% if mode %}
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</div>
</div>
{% else %}
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
{% endif %}
<div class="done-row row">
<div class="col-md-6 col-md-offset-6" style="margin-top:10px">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
</form>
</div>
</div>
{% if mode %}
<form method="POST">
<input class="radius" type='password' name='password' placeholder='Password'><br/>
<button class="radius" type='submit'>Reset Password</button>
</form>
{% else %}
<form method="POST">
<input class="radius" type='text' name='email' placeholder='Email'><br/>
<button class="radius" type='submit'>Reset Password</button>
</form>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
{% endblock %}
<script src="//cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<script src="/static/js/input.js"></script>
{% endblock %}

View File

@ -3,13 +3,16 @@
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
<div class="row">
<h1>Scoreboard</h1>
<br>
<div class="jumbotron home">
<div class="container">
<h1>Scoreboard</h1>
</div>
</div>
<div class="container main-container">
<div id="score-graph"></div>
<br>
<table id="scoreboard">
<table id="scoreboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>Place</b>

View File

@ -1,56 +1,102 @@
{% extends "base.html" %}
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.css">
<div class="row">
<h1>Setup</h1>
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.css">
<link rel="stylesheet" href="/static/css/input.css">
<link rel="stylesheet" href="/static/css/codemirror-monokai.css">
<style>
.submit-row {
padding-right: 15px;
}
</style>
{% endblock %}
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Setup</h1>
</div>
</div>
<div class="container main-container">
<div id="login-container" class="col-md-6 col-md-offset-3">
<h2 class="text-center">CTF Settings</h2>
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<input type="hidden" name="nonce" value="{{nonce}}"> {# This nonce is implemented specially in the route itself #}
<span class="input">
<input class="input-field" type="text" name="ctf_name" id="ctf_name-input" />
<label class="input-label" for="ctf_name-input">
<span class="label-content" data-content="CTF Name">CTF Name</span>
</label>
</span>
<span class="input">
<input class="input-field" type="text" name="name" id="username-input" />
<label class="input-label" for="username-input">
<span class="label-content" data-content="Username">Username</span>
</label>
</span>
<span class="input">
<input class="input-field" type="email" name="email" id="email-input" />
<label class="input-label" for="email-input">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
<br/>
</div>
</div>
<form method="POST">
<strong>CTF Name</strong>
<input class="radius" type='text' name='ctf_name' placeholder='CTF Name'><br/>
<strong>Username</strong>
<input class="radius" type='text' name='name' placeholder='Name'><br/>
<strong>Email</strong>
<input class="radius" type='text' name='email' placeholder='Email'><br/>
<strong>Password</strong>
<input class="radius" type='password' name='password' placeholder='Password'><br/>
<strong>Index Page</strong>
<div class="container" style="margin-bottom:50px;">
<h2 class="text-center">Index Page</h2>
<textarea id="pages-editor" name="html">
<div class="row">
<img class="logo" src="/static/img/logo.png">
<h3 class="text-center">Welcome to a cool CTF framework written by <a href="https://github.com/ColdHeat">Kevin Chung</a> of <a href="https://github.com/isislab">@isislab</a></h3>
<img class="logo" src="/static/img/logo.png" />
<h3 class="text-center">
Welcome to a cool CTF framework written by <a href="https://github.com/ColdHeat">Kevin Chung</a> of <a href="https://github.com/isislab">@isislab</a>
</h3>
<h4 class="text-center"><a href="/login">Click here</a> to login and setup your CTF</h4>
<h4 class="text-center">
<a href="/admin">Click here</a> to login and setup your CTF
</h4>
</div>
</textarea><br>
<input type="hidden" name="nonce" value="{{nonce}}"> {# This nonce is implemented specially in the route itself #}
<button class="radius" type='submit'>Login</button>
</textarea>
</div>
<div class="container main-container" style="margin-bottom:100px;">
<div id="login-container" class="col-md-6 col-md-offset-3">
<div class="submit-row text-center">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined">Submit</button>
</div>
</div>
</div>
</form>
</div>
{% endblock %}
{% block scripts %}
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.min.js"></script>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "text/html"
});
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<script src="/static/js/input.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/4.8.0/codemirror.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.2.0/mode/xml/xml.min.js"></script>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "xml",
htmlMode: true,
theme: 'monokai'
});
</script>
{% endblock %}

View File

@ -1,28 +1,35 @@
{% extends "base.html" %}
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css">
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css">
{% endblock %}
<div class="row">
<h1 id="team-id">{{ team.name }}</h1>
<h2 id="team-place" class="text-center">
{%if place %}
{{ place }} <small>place</small>
{% endif %}
</h2>
<h2 id="team-score" class="text-center">
{%if score %}
{{ score }} <small>points</small>
{% endif %}
</h2>
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1 id="team-id">{{ team.name }}</h1>
</div>
</div>
<div class="container">
<div class="team-info">
<h2 id="team-place" class="text-center">
{%if place %}
{{ place }} <small>place</small>
{% endif %}
</h2>
<h2 id="team-score" class="text-center">
{%if score %}
{{ score }} <small>points</small>
{% endif %}
</h2>
</div>
<br>
<div id="keys-pie-graph"></div>
<div id="categories-pie-graph"></div>
<div id="score-graph"></div>
<table>
<table class="table table-striped">
<thead>
<tr>
<td><b>Challenge</b></td>
@ -37,9 +44,8 @@
{% endfor %}
</tbody>
</table>
<div id="score-graph"></div>
</div>
{% endblock %}
{% block scripts %}

View File

@ -1,15 +1,19 @@
{% extends "base.html" %}
{% block content %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/c3/0.4.0/c3.min.css">
{% endblock %}
<div class="row">
<h1>Teams</h1>
<br>
<table id="teamsboard">
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Teams</h1>
</div>
</div>
<div class="container main-container">
<table id="teamsboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>ID</b></td>
<td><b>Team</b></td>
<td><b>Website</b></td>
<td><b>Affiliation</b></td>
@ -19,9 +23,8 @@
<tbody>
{% for team in teams %}
<tr>
<td class="team-id">{{ team.id }}</td>
<td><a href="/team/{{ team.id }}">{{ team.name | truncate(32) }}</a></td>
<td>{% if team.website and team.website.startswith('http') %}<a href="{{ team.website }}">{{ team.website }}</a>{% endif %}</td>
<td><a href="/team/{{ team.id }}">{{ team.name }}</a></td>
<td>{% if team.website and team.website.startswith('http://') %}<a href="{{ team.website }}">{{ team.website }}</a>{% endif %}</td>
<td><span>{% if team.affiliation %}{{ team.affiliation }}{% endif %}</span></td>
<td><span>{% if team.country %}{{ team.country }}{% endif %}</span></td>
</tr>
@ -32,7 +35,7 @@
<div class="text-center">Page
<br>
{% for page in range(1, team_pages + 1) %}
<a href="/teams/{{ page }}">{{ page }}</a>
<a href="/teams/{{ page }}">{{ page }}</a>
{% endfor %}
<a href="">
</div>