mirror of https://github.com/JohnHammond/CTFd.git
Starting containers
parent
c769f5865f
commit
a0d7d8abcb
|
@ -1,6 +1,6 @@
|
|||
from flask import render_template, request, redirect, abort, jsonify, url_for, session, Blueprint
|
||||
from CTFd.utils import sha512, is_safe_url, authed, admins_only, is_admin, unix_time, unix_time_millis, get_config, set_config, sendmail, rmdir
|
||||
from CTFd.models import db, Teams, Solves, Awards, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||
from CTFd.utils import sha512, is_safe_url, authed, admins_only, is_admin, unix_time, unix_time_millis, get_config, set_config, sendmail, rmdir, create_container
|
||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||
from itsdangerous import TimedSerializer, BadTimeSignature
|
||||
from sqlalchemy.sql import and_, or_, not_
|
||||
from sqlalchemy.sql.expression import union_all
|
||||
|
@ -223,6 +223,26 @@ def delete_page(pageroute):
|
|||
return '1'
|
||||
|
||||
|
||||
@admin.route('/admin/containers', methods=['GET'])
|
||||
@admins_only
|
||||
def list_container():
|
||||
containers = Containers.query.all()
|
||||
return render_template('admin/containers.html', containers=containers)
|
||||
|
||||
|
||||
@admin.route('/admin/containers/new', methods=['POST'])
|
||||
@admins_only
|
||||
def new_container():
|
||||
name = request.form.get('name')
|
||||
buildfile = request.form.get('buildfile')
|
||||
files = request.files.getlist('files[]')
|
||||
print name
|
||||
print buildfile
|
||||
print files
|
||||
create_container(name=name, buildfile=buildfile, files=files)
|
||||
|
||||
|
||||
|
||||
@admin.route('/admin/chals', methods=['POST', 'GET'])
|
||||
@admins_only
|
||||
def admin_chals():
|
||||
|
|
|
@ -38,6 +38,19 @@ class Pages(db.Model):
|
|||
return "<Tag {0} for challenge {1}>".format(self.tag, self.chal)
|
||||
|
||||
|
||||
class Containers(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(80))
|
||||
buildfile = db.Column(db.Text)
|
||||
|
||||
def __init__(self, name, buildfile):
|
||||
self.name = name
|
||||
self.buildfile = buildfile
|
||||
|
||||
def __repr__(self):
|
||||
return "<Container ID:(0) {1}>".format(self.id, self.name)
|
||||
|
||||
|
||||
class Challenges(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(80))
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<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/containers">Containers</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>
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
{% extends "admin/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="modal fade" id="create-container-modal" tabindex="-1" role="dialog" aria-labelledby="container-modal-label">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="container-modal-label">Create Container</h4>
|
||||
</div>
|
||||
<form method="POST" action="/admin/containers/new" enctype="multipart/form-data">
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="form-control" name="name" placeholder="Enter container name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="buildfile-editor" class="control-label">Build File</label>
|
||||
<textarea id="buildfile-editor" class="form-control" name="buildfile" rows="10"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="container-files">File input</label>
|
||||
<input type="file" name="files[]" id="container-files" multiple>
|
||||
<p class="help-block">These files are uploaded alongside your buildfile</p>
|
||||
</div>
|
||||
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Create</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<br>
|
||||
<div style="text-align:center">
|
||||
<h1>Containers</h1>
|
||||
<button class="btn btn-theme btn-outlined create-challenge" data-toggle="modal" data-target="#create-container-modal">
|
||||
New Container
|
||||
</button>
|
||||
</div>
|
||||
<br>
|
||||
{% if containers %}
|
||||
<table id="teamsboard">
|
||||
<thead>
|
||||
<tr>
|
||||
<td><b>Status</b>
|
||||
</td>
|
||||
<td><b>Name</b>
|
||||
</td>
|
||||
<td><b>IP Address</b>
|
||||
</td>
|
||||
<td><b>Memory</b>
|
||||
</td>
|
||||
<td><b>Disk</b>
|
||||
</td>
|
||||
<td><b>Settings</b>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in containers %}
|
||||
<tr>
|
||||
<td>{{ c.name }}</td>
|
||||
<td>{{ c.status }}</td>
|
||||
<td>{{ c.ip_address }}</td>
|
||||
<td>{{ c.memory }} <sub>MB</sub></td>
|
||||
<td>{{ c.disk }} <sub>GB</sub></td>
|
||||
<td>
|
||||
<span>
|
||||
<i class="fa fa-pencil-square-o"></i>
|
||||
<i class="fa fa-times"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
|
@ -1,66 +0,0 @@
|
|||
{% extends "admin/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div id="create-droplet-modal" class="reveal-modal" data-reveal>
|
||||
<h2 class="text-center">Create Droplet</h2>
|
||||
|
||||
<p></p>
|
||||
<a class="close-reveal-modal">×</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<br>
|
||||
<h1>Hosts</h1>
|
||||
<br>
|
||||
{% 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 %}
|
||||
<table id="teamsboard">
|
||||
<thead>
|
||||
<tr>
|
||||
<td><b>ID</b>
|
||||
</td>
|
||||
<td><b>Status</b>
|
||||
</td>
|
||||
<td><b>Name</b>
|
||||
</td>
|
||||
<td><b>IP Address</b>
|
||||
</td>
|
||||
<td><b>Memory</b>
|
||||
</td>
|
||||
<td><b>Disk</b>
|
||||
</td>
|
||||
<td><b>Settings</b>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for host in hosts %}
|
||||
<tr>
|
||||
<td>{{ host.id }}</td>
|
||||
<td>{{ host.status }}</td>
|
||||
<td>{{ host.name }}</td>
|
||||
<td>{{ host.ip_address }}</td>
|
||||
<td>{{ host.memory }} <sub>MB</sub></td>
|
||||
<td>{{ host.disk }} <sub>GB</sub></td>
|
||||
<td>
|
||||
<span>
|
||||
<i class="fa fa-pencil-square-o"></i>
|
||||
<i class="fa fa-times"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="#" data-reveal-id="create-droplet-modal" class="radius button">Create New Host</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
|
@ -1,6 +1,7 @@
|
|||
from CTFd.models import db, WrongKeys, Pages, Config, Tracking, Teams
|
||||
|
||||
from six.moves.urllib.parse import urlparse, urljoin
|
||||
from six.moves.urllib.parse import urlparse, urljoin
|
||||
from werkzeug.utils import secure_filename
|
||||
from functools import wraps
|
||||
from flask import current_app as app, g, request, redirect, url_for, session, render_template, abort
|
||||
from itsdangerous import Signer, BadSignature
|
||||
|
@ -21,6 +22,8 @@ import re
|
|||
import time
|
||||
import smtplib
|
||||
import email
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
def init_logs(app):
|
||||
logger_keys = logging.getLogger('keys')
|
||||
|
@ -381,3 +384,30 @@ def validate_url(url):
|
|||
def sha512(string):
|
||||
return hashlib.sha512(string).hexdigest()
|
||||
|
||||
|
||||
def can_create_container():
|
||||
try:
|
||||
output = subprocess.check_output(['docker', 'version'])
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def create_container(name, buildfile, files):
|
||||
if not can_create_container():
|
||||
return False
|
||||
folder = tempfile.mkdtemp(prefix='ctfd')
|
||||
tmpfile = tempfile.NamedTemporaryFile(dir=folder, delete=False)
|
||||
tmpfile.write(buildfile)
|
||||
tmpfile.close()
|
||||
|
||||
for f in files:
|
||||
filename = os.path.basename(f.filename)
|
||||
f.save(os.path.join(folder, filename))
|
||||
|
||||
# docker build -f tmpfile.name -t name
|
||||
try:
|
||||
subprocess.call(['docker', 'build', '-f', tmpfile.name, '-t', name])
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
Loading…
Reference in New Issue