Ensured testing of TLS usage for each Docker API call. Stopped unintentional KeyError in finding unused ports

master
John Hammond 2020-05-06 21:12:50 -04:00
parent 44aa8af317
commit 30219cd549
1 changed files with 765 additions and 527 deletions

View File

@ -4,9 +4,30 @@ from CTFd.utils.user import get_ip
from CTFd.utils.uploads import delete_file
from CTFd.plugins import register_plugin_assets_directory, bypass_csrf_protection
from CTFd.schemas.tags import TagSchema
from CTFd.models import db, ma, Challenges, Teams, Users, Solves, Fails, Flags, Files, Hints, Tags, ChallengeFiles
from CTFd.utils.decorators import admins_only, authed_only, during_ctf_time_only, require_verified_emails
from CTFd.utils.decorators.visibility import check_challenge_visibility, check_score_visibility
from CTFd.models import (
db,
ma,
Challenges,
Teams,
Users,
Solves,
Fails,
Flags,
Files,
Hints,
Tags,
ChallengeFiles,
)
from CTFd.utils.decorators import (
admins_only,
authed_only,
during_ctf_time_only,
require_verified_emails,
)
from CTFd.utils.decorators.visibility import (
check_challenge_visibility,
check_score_visibility,
)
from CTFd.utils.user import get_current_team
from CTFd.utils.user import get_current_user
from CTFd.utils.user import is_admin, authed
@ -16,9 +37,25 @@ from CTFd.api.v1.scoreboard import ScoreboardDetail
import CTFd.utils.scores
from CTFd.api.v1.challenges import ChallengeList, Challenge
from flask_restplus import Namespace, Resource
from flask import request, Blueprint, jsonify, abort, render_template, url_for, redirect, session
from flask import (
request,
Blueprint,
jsonify,
abort,
render_template,
url_for,
redirect,
session,
)
from flask_wtf import FlaskForm
from wtforms import TextField, SubmitField, BooleanField, HiddenField, FileField, SelectMultipleField
from wtforms import (
TextField,
SubmitField,
BooleanField,
HiddenField,
FileField,
SelectMultipleField,
)
from wtforms.validators import DataRequired, ValidationError
from werkzeug.utils import secure_filename
import requests
@ -30,10 +67,12 @@ import hashlib
import random
from CTFd.plugins import register_admin_plugin_menu_bar
class DockerConfig(db.Model):
"""
Docker Config Model. This model stores the config for docker API connections.
"""
id = db.Column(db.Integer, primary_key=True)
hostname = db.Column("hostname", db.String(64), index=True)
tls_enabled = db.Column("tls_enabled", db.Boolean, index=True)
@ -42,10 +81,12 @@ class DockerConfig(db.Model):
client_key = db.Column("client_key", db.String, index=True)
repositories = db.Column("repositories", db.String, index=True)
class DockerChallengeTracker(db.Model):
"""
Docker Container Tracker. This model stores the users/teams active docker containers.
"""
id = db.Column(db.Integer, primary_key=True)
team_id = db.Column("team_id", db.String, index=True)
user_id = db.Column("user_id", db.String, index=True)
@ -53,24 +94,37 @@ class DockerChallengeTracker(db.Model):
timestamp = db.Column("timestamp", db.Integer, index=True)
revert_time = db.Column("revert_time", db.Integer, index=True)
instance_id = db.Column("instance_id", db.String, index=True)
ports = db.Column('ports', db.String, index=True)
host = db.Column('host', db.String, index=True)
ports = db.Column("ports", db.String, index=True)
host = db.Column("host", db.String, index=True)
class DockerConfigForm(FlaskForm):
"""
Docker Config Form. This Form Handles the Docker Config data.
"""
id = HiddenField()
hostname = TextField('Docker Hostname', render_kw={"placeholder": "10.10.10.10:2376", "autofocus" : "true"}, validators=[DataRequired("Hostname name is required")])
tls_enabled = BooleanField('TLS Enabled?')
ca_cert = FileField('CA Cert')
client_cert = FileField('Client Cert')
client_key = FileField('Client Key')
repositories = SelectMultipleField('Repositories')
submit = SubmitField('Submit')
hostname = TextField(
"Docker Hostname",
render_kw={"placeholder": "10.10.10.10:2376", "autofocus": "true"},
validators=[DataRequired("Hostname name is required")],
)
tls_enabled = BooleanField("TLS Enabled?")
ca_cert = FileField("CA Cert")
client_cert = FileField("Client Cert")
client_key = FileField("Client Key")
repositories = SelectMultipleField("Repositories")
submit = SubmitField("Submit")
def define_docker_admin(app):
admin_docker_config = Blueprint('admin_docker_config', __name__, template_folder='templates', static_folder='assets')
admin_docker_config = Blueprint(
"admin_docker_config",
__name__,
template_folder="templates",
static_folder="assets",
)
@admin_docker_config.route("/admin/docker_config", methods=["GET", "POST"])
@admins_only
def docker_config():
@ -81,22 +135,31 @@ def define_docker_admin(app):
b = docker
else:
b = DockerConfig()
try: ca_cert = request.files['ca_cert'].stream.read()
except: ca_cert = ''
try: client_cert = request.files['client_cert'].stream.read()
except: client_cert = ''
try: client_key = request.files['client_key'].stream.read()
except: client_key = ''
if len(ca_cert) != 0: b.ca_cert = ca_cert
if len(client_cert) != 0: b.client_cert = client_cert
if len(client_key) != 0: b.client_key = client_key
try:
ca_cert = request.files["ca_cert"].stream.read()
except:
ca_cert = ""
try:
client_cert = request.files["client_cert"].stream.read()
except:
client_cert = ""
try:
client_key = request.files["client_key"].stream.read()
except:
client_key = ""
if len(ca_cert) != 0:
b.ca_cert = ca_cert
if len(client_cert) != 0:
b.client_cert = client_cert
if len(client_key) != 0:
b.client_key = client_key
b.hostname = form.hostname.data
b.tls_enabled = form.tls_enabled.data
if not b.tls_enabled:
b.ca_cert = None
b.client_cert = None
b.client_key = None
b.repositories = ','.join(form.repositories.data) or None
b.repositories = ",".join(form.repositories.data) or None
db.session.add(b)
db.session.commit()
docker = DockerConfig.query.filter_by(id=1).first()
@ -110,15 +173,24 @@ def define_docker_admin(app):
form.repositories.choices = [(d, d) for d in repos]
dconfig = DockerConfig.query.first()
try:
selected_repos = dconfig.repositories.split(',')
selected_repos = dconfig.repositories.split(",")
except:
selected_repos = []
return render_template("docker_config.html", config=dconfig, form=form, repos=selected_repos)
return render_template(
"docker_config.html", config=dconfig, form=form, repos=selected_repos
)
app.register_blueprint(admin_docker_config)
def define_docker_status(app):
admin_docker_status = Blueprint('admin_docker_status', __name__, template_folder='templates', static_folder='assets')
admin_docker_status = Blueprint(
"admin_docker_status",
__name__,
template_folder="templates",
static_folder="assets",
)
@admin_docker_status.route("/admin/docker_status", methods=["GET", "POST"])
@admins_only
def docker_admin():
@ -132,25 +204,32 @@ def define_docker_status(app):
name = Users.query.filter_by(id=i.user_id).first()
i.user_id = name.name
return render_template("admin_docker_status.html", dockers=docker_tracker)
app.register_blueprint(admin_docker_status)
kill_container = Namespace("nuke", description='Endpoint to nuke containers')
@kill_container.route("", methods=['POST','GET'])
kill_container = Namespace("nuke", description="Endpoint to nuke containers")
@kill_container.route("", methods=["POST", "GET"])
class KillContainerAPI(Resource):
@admins_only
def get(self):
container = request.args.get('container')
full = request.args.get('all')
container = request.args.get("container")
full = request.args.get("all")
docker_config = DockerConfig.query.filter_by(id=1).first()
docker_tracker = DockerChallengeTracker.query.all()
if full == "true":
for c in docker_tracker:
delete_container(docker_config, c.instance_id)
DockerChallengeTracker.query.filter_by(instance_id=c.instance_id).delete()
DockerChallengeTracker.query.filter_by(
instance_id=c.instance_id
).delete()
db.session.commit()
db.session.close()
elif container != 'null' and container in [c.instance_id for c in docker_tracker]:
elif container != "null" and container in [
c.instance_id for c in docker_tracker
]:
delete_container(docker_config, container)
DockerChallengeTracker.query.filter_by(instance_id=container).delete()
db.session.commit()
@ -159,13 +238,14 @@ class KillContainerAPI(Resource):
return False
return True
# For the Docker Config Page. Gets the Current Repositories available on the Docker Server.
def get_repositories(docker, tags=False, repos=False):
tls = docker.tls_enabled
if not tls:
prefix = 'http'
prefix = "http"
else:
prefix = 'https'
prefix = "https"
try:
ca = docker.ca_cert
client = docker.client_cert
@ -183,10 +263,14 @@ def get_repositories(docker, tags=False, repos=False):
except:
return []
host = docker.hostname
URL_TEMPLATE = '%s://%s' % (prefix, host)
URL_TEMPLATE = "%s://%s" % (prefix, host)
if tls:
try:
r = requests.get(url="%s/images/json?all=1" % URL_TEMPLATE, cert=CERT, verify=ca_file.name)
r = requests.get(
url="%s/images/json?all=1" % URL_TEMPLATE,
cert=CERT,
verify=ca_file.name,
)
except:
return []
else:
@ -196,23 +280,24 @@ def get_repositories(docker, tags=False, repos=False):
return []
result = list()
for i in r.json():
if not i['RepoTags'] == None:
if not i['RepoTags'][0].split(':')[0] == '<none>':
if not i["RepoTags"] == None:
if not i["RepoTags"][0].split(":")[0] == "<none>":
if repos:
if not i['RepoTags'][0].split(':')[0] in repos:
if not i["RepoTags"][0].split(":")[0] in repos:
continue
if not tags:
result.append(i['RepoTags'][0].split(':')[0])
result.append(i["RepoTags"][0].split(":")[0])
else:
result.append(i['RepoTags'][0])
result.append(i["RepoTags"][0])
return list(set(result))
def get_unavailable_ports(docker):
tls = docker.tls_enabled
if not tls:
prefix = 'http'
prefix = "http"
else:
prefix = 'https'
prefix = "https"
try:
ca = docker.ca_cert
client = docker.client_cert
@ -230,21 +315,39 @@ def get_unavailable_ports(docker):
except:
return []
host = docker.hostname
URL_TEMPLATE = '%s://%s' % (prefix, host)
r = requests.get(url="%s/containers/json?all=1" % URL_TEMPLATE, cert=CERT, verify=ca_file.name)
URL_TEMPLATE = "%s://%s" % (prefix, host)
if tls:
try:
r = requests.get(
url="%s/containers/json?all=1" % URL_TEMPLATE,
cert=CERT,
verify=ca_file.name,
)
except:
return []
else:
try:
r = requests.get(url="%s/containers/json?all=1" % URL_TEMPLATE)
except:
return []
result = list()
for i in r.json():
if not i['Ports'] == []:
for p in i['Ports']:
result.append(p['PublicPort'])
if not i["Ports"] == []:
for p in i["Ports"]:
if "PublicPort" in p:
result.append(p["PublicPort"])
return result
def get_required_ports(docker, image):
tls = docker.tls_enabled
if not tls:
prefix = 'http'
prefix = "http"
else:
prefix = 'https'
prefix = "https"
try:
ca = docker.ca_cert
client = docker.client_cert
@ -262,18 +365,33 @@ def get_required_ports(docker, image):
except:
return []
host = docker.hostname
URL_TEMPLATE = '%s://%s' % (prefix, host)
r = requests.get(url="%s/images/%s/json?all=1" % (URL_TEMPLATE, image), cert=CERT, verify=ca_file.name)
result = r.json()['ContainerConfig']['ExposedPorts'].keys()
URL_TEMPLATE = "%s://%s" % (prefix, host)
if tls:
try:
r = requests.get(
url="%s/images/%s/json?all=1" % (URL_TEMPLATE, image),
cert=CERT,
verify=ca_file.name,
)
except:
return []
else:
try:
r = requests.get(url="%s/images/%s/json?all=1" % (URL_TEMPLATE, image))
except:
return []
result = r.json()["ContainerConfig"]["ExposedPorts"].keys()
return result
def create_container(docker, image, team, portbl):
tls = docker.tls_enabled
if not tls:
prefix = 'http'
prefix = "http"
else:
prefix = 'https'
prefix = "https"
try:
ca = docker.ca_cert
client = docker.client_cert
@ -291,16 +409,16 @@ def create_container(docker, image, team, portbl):
except:
return []
host = docker.hostname
URL_TEMPLATE = '%s://%s' % (prefix, host)
URL_TEMPLATE = "%s://%s" % (prefix, host)
needed_ports = get_required_ports(docker, image)
team = hashlib.md5(team.encode("utf-8")).hexdigest()[:10]
container_name = "%s_%s" % (image.split(':')[1], team)
container_name = "%s_%s" % (image.split(":")[1], team)
assigned_ports = dict()
for i in needed_ports:
while True:
assigned_port = random.choice(range(30000, 60000))
if assigned_port not in portbl:
assigned_ports['%s/tcp' % assigned_port] = { }
assigned_ports["%s/tcp" % assigned_port] = {}
break
ports = dict()
bindings = dict()
@ -308,19 +426,66 @@ def create_container(docker, image, team, portbl):
for i in needed_ports:
ports[i] = {}
bindings[i] = [{"HostPort": tmp_ports.pop()}]
headers = {'Content-Type': "application/json"}
data = json.dumps({"Image": image, "ExposedPorts": ports, "HostConfig" : { "PortBindings" : bindings } })
r = requests.post(url="%s/containers/create?name=%s" % (URL_TEMPLATE, container_name), cert=CERT, verify=ca_file.name, data=data, headers=headers)
headers = {"Content-Type": "application/json"}
data = json.dumps(
{
"Image": image,
"ExposedPorts": ports,
"HostConfig": {"PortBindings": bindings},
}
)
if tls:
try:
r = requests.get(
url="%s/containers/create?name=%s" % (URL_TEMPLATE, container_name),
cert=CERT,
verify=ca_file.name,
data=data,
headers=headers,
)
except:
return []
else:
try:
r = requests.get(
url="%s/containers/create?name=%s" % (URL_TEMPLATE, container_name),
data=data,
headers=headers,
)
except:
return []
result = r.json()
s = requests.post(url="%s/containers/%s/start" % (URL_TEMPLATE, result['Id']), cert=CERT, verify=ca_file.name, headers=headers)
if tls:
try:
s = requests.post(
url="%s/containers/%s/start" % (URL_TEMPLATE, result["Id"]),
cert=CERT,
verify=ca_file.name,
headers=headers,
)
except:
return []
else:
try:
s = requests.post(
url="%s/containers/%s/start" % (URL_TEMPLATE, result["Id"]),
headers=headers,
)
except:
return []
return result, data
def delete_container(docker, instance_id):
tls = docker.tls_enabled
if not tls:
prefix = 'http'
prefix = "http"
else:
prefix = 'https'
prefix = "https"
try:
ca = docker.ca_cert
client = docker.client_cert
@ -338,26 +503,51 @@ def delete_container(docker, instance_id):
except:
return []
host = docker.hostname
URL_TEMPLATE = '%s://%s' % (prefix, host)
headers = {'Content-Type': "application/json"}
r = requests.delete(url="%s/containers/%s?force=true" % (URL_TEMPLATE, instance_id), cert=CERT, verify=ca_file.name, headers=headers)
URL_TEMPLATE = "%s://%s" % (prefix, host)
headers = {"Content-Type": "application/json"}
if tls:
try:
r = requests.delete(
url="%s/containers/%s?force=true" % (URL_TEMPLATE, instance_id),
cert=CERT,
verify=ca_file.name,
headers=headers,
)
except:
return []
else:
try:
r = requests.delete(
url="%s/containers/%s?force=true" % (URL_TEMPLATE, instance_id),
headers=headers,
)
except:
return []
return True
class DockerChallengeType(BaseChallenge):
id = "docker"
name = "docker"
templates = {
'create': '/plugins/docker_challenges/assets/create.html',
'update': '/plugins/docker_challenges/assets/update.html',
'view': '/plugins/docker_challenges/assets/view.html',
"create": "/plugins/docker_challenges/assets/create.html",
"update": "/plugins/docker_challenges/assets/update.html",
"view": "/plugins/docker_challenges/assets/view.html",
}
scripts = {
'create': '/plugins/docker_challenges/assets/create.js',
'update': '/plugins/docker_challenges/assets/update.js',
'view': '/plugins/docker_challenges/assets/view.js',
"create": "/plugins/docker_challenges/assets/create.js",
"update": "/plugins/docker_challenges/assets/update.js",
"view": "/plugins/docker_challenges/assets/view.js",
}
route = '/plugins/docker_challenges/assets'
blueprint = Blueprint('docker_challenges', __name__, template_folder='templates', static_folder='assets')
route = "/plugins/docker_challenges/assets"
blueprint = Blueprint(
"docker_challenges",
__name__,
template_folder="templates",
static_folder="assets",
)
@staticmethod
def update(challenge, request):
@ -408,21 +598,21 @@ class DockerChallengeType(BaseChallenge):
"""
challenge = DockerChallenge.query.filter_by(id=challenge.id).first()
data = {
'id': challenge.id,
'name': challenge.name,
'value': challenge.value,
'docker_image': challenge.docker_image,
'description': challenge.description,
'category': challenge.category,
'state': challenge.state,
'max_attempts': challenge.max_attempts,
'type': challenge.type,
'type_data': {
'id': DockerChallengeType.id,
'name': DockerChallengeType.name,
'templates': DockerChallengeType.templates,
'scripts': DockerChallengeType.scripts,
}
"id": challenge.id,
"name": challenge.name,
"value": challenge.value,
"docker_image": challenge.docker_image,
"description": challenge.description,
"category": challenge.category,
"state": challenge.state,
"max_attempts": challenge.max_attempts,
"type": challenge.type,
"type_data": {
"id": DockerChallengeType.id,
"name": DockerChallengeType.name,
"templates": DockerChallengeType.templates,
"scripts": DockerChallengeType.scripts,
},
}
return data
@ -474,11 +664,25 @@ class DockerChallengeType(BaseChallenge):
docker = DockerConfig.query.filter_by(id=1).first()
try:
if is_teams_mode():
docker_containers = DockerChallengeTracker.query.filter_by(docker_image=challenge.docker_image).filter_by(team_id=team.id).first()
docker_containers = (
DockerChallengeTracker.query.filter_by(
docker_image=challenge.docker_image
)
.filter_by(team_id=team.id)
.first()
)
else:
docker_containers = DockerChallengeTracker.query.filter_by(docker_image=challenge.docker_image).filter_by(user_id=user.id).first()
docker_containers = (
DockerChallengeTracker.query.filter_by(
docker_image=challenge.docker_image
)
.filter_by(user_id=user.id)
.first()
)
delete_container(docker, docker_containers.instance_id)
DockerChallengeTracker.query.filter_by(instance_id=docker_containers.instance_id).delete()
DockerChallengeTracker.query.filter_by(
instance_id=docker_containers.instance_id
).delete()
except:
pass
solve = Solves(
@ -515,19 +719,25 @@ class DockerChallengeType(BaseChallenge):
db.session.commit()
db.session.close()
class DockerChallenge(Challenges):
__mapper_args__ = {'polymorphic_identity': 'docker'}
id = db.Column(None, db.ForeignKey('challenges.id'), primary_key=True)
__mapper_args__ = {"polymorphic_identity": "docker"}
id = db.Column(None, db.ForeignKey("challenges.id"), primary_key=True)
docker_image = db.Column(db.String, index=True)
# API
container_namespace = Namespace("container", description='Endpoint to interact with containers')
@container_namespace.route("", methods=['POST','GET'])
container_namespace = Namespace(
"container", description="Endpoint to interact with containers"
)
@container_namespace.route("", methods=["POST", "GET"])
class ContainerAPI(Resource):
@authed_only
# I wish this was Post... Issues with API/CSRF and whatnot. Open to a Issue solving this.
def get(self):
container = request.args.get('name')
container = request.args.get("name")
if not container:
return abort(403)
docker = DockerConfig.query.filter_by(id=1).first()
@ -538,55 +748,86 @@ class ContainerAPI(Resource):
session = get_current_team()
# First we'll delete all old docker containers (+2 hours)
for i in containers:
if int(session.id) == int(i.team_id) and (unix_time(datetime.utcnow()) - int(i.timestamp)) >= 7200:
if (
int(session.id) == int(i.team_id)
and (unix_time(datetime.utcnow()) - int(i.timestamp)) >= 7200
):
delete_container(docker, i.instance_id)
DockerChallengeTracker.query.filter_by(instance_id=i.instance_id).delete()
DockerChallengeTracker.query.filter_by(
instance_id=i.instance_id
).delete()
db.session.commit()
check = DockerChallengeTracker.query.filter_by(team_id=session.id).filter_by(docker_image=container).first()
check = (
DockerChallengeTracker.query.filter_by(team_id=session.id)
.filter_by(docker_image=container)
.first()
)
else:
session = get_current_user()
for i in containers:
if int(session.id) == int(i.user_id) and (unix_time(datetime.utcnow()) - int(i.timestamp)) >= 7200:
if (
int(session.id) == int(i.user_id)
and (unix_time(datetime.utcnow()) - int(i.timestamp)) >= 7200
):
delete_container(docker, i.instance_id)
DockerChallengeTracker.query.filter_by(instance_id=i.instance_id).delete()
DockerChallengeTracker.query.filter_by(
instance_id=i.instance_id
).delete()
db.session.commit()
check = DockerChallengeTracker.query.filter_by(user_id=session.id).filter_by(docker_image=container).first()
check = (
DockerChallengeTracker.query.filter_by(user_id=session.id)
.filter_by(docker_image=container)
.first()
)
# If this container is already created, we don't need another one.
if check != None and not (unix_time(datetime.utcnow()) - int(check.timestamp)) >= 300:
if (
check != None
and not (unix_time(datetime.utcnow()) - int(check.timestamp)) >= 300
):
return abort(403)
# The exception would be if we are reverting a box. So we'll delete it if it exists and has been around for more than 5 minutes.
elif check != None:
delete_container(docker, check.instance_id)
if is_teams_mode():
DockerChallengeTracker.query.filter_by(team_id=session.id).filter_by(docker_image=container).delete()
DockerChallengeTracker.query.filter_by(team_id=session.id).filter_by(
docker_image=container
).delete()
else:
DockerChallengeTracker.query.filter_by(user_id=session.id).filter_by(docker_image=container).delete()
DockerChallengeTracker.query.filter_by(user_id=session.id).filter_by(
docker_image=container
).delete()
db.session.commit()
portsbl = get_unavailable_ports(docker)
create = create_container(docker, container, session.name, portsbl)
ports = json.loads(create[1])['HostConfig']['PortBindings'].values()
ports = json.loads(create[1])["HostConfig"]["PortBindings"].values()
entry = DockerChallengeTracker(
team_id=session.id if is_teams_mode() else None,
user_id=session.id if not is_teams_mode() else None,
docker_image=container,
timestamp=unix_time(datetime.utcnow()),
revert_time=unix_time(datetime.utcnow()) + 300,
instance_id = create[0]['Id'],
ports = ','.join([p[0]['HostPort'] for p in ports]),
host = str(docker.hostname).split(':')[0]
instance_id=create[0]["Id"],
ports=",".join([p[0]["HostPort"] for p in ports]),
host=str(docker.hostname).split(":")[0],
)
db.session.add(entry)
db.session.commit()
db.session.close()
return
active_docker_namespace = Namespace("docker", description='Endpoint to retrieve User Docker Image Status')
@active_docker_namespace.route("", methods=['POST','GET'])
active_docker_namespace = Namespace(
"docker", description="Endpoint to retrieve User Docker Image Status"
)
@active_docker_namespace.route("", methods=["POST", "GET"])
class DockerStatus(Resource):
"""
The Purpose of this API is to retrieve a public JSON string of all docker containers
in use by the current team/user.
"""
@authed_only
def get(self):
docker = DockerConfig.query.filter_by(id=1).first()
@ -598,29 +839,32 @@ class DockerStatus(Resource):
tracker = DockerChallengeTracker.query.filter_by(user_id=session.id)
data = list()
for i in tracker:
data.append({
'id' : i.id,
'team_id' : i.team_id,
'user_id' : i.user_id,
'docker_image' : i.docker_image,
'timestamp' : i.timestamp,
'revert_time' : i.revert_time,
'instance_id' : i.instance_id,
'ports' : i.ports.split(','),
'host' : str(docker.hostname).split(':')[0]
})
return {
'success' : True,
'data' : data
data.append(
{
"id": i.id,
"team_id": i.team_id,
"user_id": i.user_id,
"docker_image": i.docker_image,
"timestamp": i.timestamp,
"revert_time": i.revert_time,
"instance_id": i.instance_id,
"ports": i.ports.split(","),
"host": str(docker.hostname).split(":")[0],
}
)
return {"success": True, "data": data}
docker_namespace = Namespace("docker", description='Endpoint to retrieve dockerstuff')
@docker_namespace.route("", methods=['POST','GET'])
docker_namespace = Namespace("docker", description="Endpoint to retrieve dockerstuff")
@docker_namespace.route("", methods=["POST", "GET"])
class DockerAPI(Resource):
"""
This is for creating Docker Challenges. The purpose of this API is to populate the Docker Image Select form
object in the Challenge Creation Screen.
"""
@admins_only
def get(self):
docker = DockerConfig.query.filter_by(id=1).first()
@ -628,28 +872,22 @@ class DockerAPI(Resource):
if images:
data = list()
for i in images:
data.append({'name':i})
return {
'success' : True,
'data' : data
}
data.append({"name": i})
return {"success": True, "data": data}
else:
return {
'success' : False,
'data' : [
{
'name':'Error in Docker Config!'
}
]
}, 400
return (
{"success": False, "data": [{"name": "Error in Docker Config!"}]},
400,
)
def load(app):
app.db.create_all()
CHALLENGE_CLASSES['docker'] = DockerChallengeType
register_plugin_assets_directory(app, base_path='/plugins/docker_challenges/assets')
CHALLENGE_CLASSES["docker"] = DockerChallengeType
register_plugin_assets_directory(app, base_path="/plugins/docker_challenges/assets")
define_docker_admin(app)
define_docker_status(app)
CTFd_API_v1.add_namespace(docker_namespace, '/docker')
CTFd_API_v1.add_namespace(container_namespace, '/container')
CTFd_API_v1.add_namespace(active_docker_namespace, '/docker_status')
CTFd_API_v1.add_namespace(kill_container, '/nuke')
CTFd_API_v1.add_namespace(docker_namespace, "/docker")
CTFd_API_v1.add_namespace(container_namespace, "/container")
CTFd_API_v1.add_namespace(active_docker_namespace, "/docker_status")
CTFd_API_v1.add_namespace(kill_container, "/nuke")