Fix hint loading for admins with /api/v1/hints/<id>?preview=true (#786)

* Fix hint loading for admins by adding /api/v1/hints/<id>?preview=true for use by admins
* Add tests for admin Hint preview
selenium-screenshot-testing
Kevin Chung 2018-12-06 21:46:47 -05:00 committed by GitHub
parent afdfaa15da
commit 5cedcb7372
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 112 additions and 2 deletions

View File

@ -3,7 +3,7 @@ from flask_restplus import Namespace, Resource
from CTFd.models import db, Hints, HintUnlocks
from CTFd.plugins.challenges import get_chal_class
from CTFd.utils.dates import ctf_ended
from CTFd.utils.user import get_current_user
from CTFd.utils.user import get_current_user, is_admin
from CTFd.schemas.hints import HintSchema
from CTFd.utils.decorators import (
during_ctf_time_only,
@ -75,6 +75,10 @@ class Hint(Resource):
if unlocked:
view = 'unlocked'
if is_admin():
if request.args.get('preview', False):
view = 'admin'
response = HintSchema(view=view).dump(hint)
if response.errors:

View File

@ -1,6 +1,55 @@
function hint(id) {
return fetch(script_root + '/api/v1/hints/' + id + '?preview=true', {
method: 'GET',
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(function (response) {
return response.json();
});
}
function loadhint(hintid) {
var md = window.markdownit({
html: true,
});
hint(hintid).then(function (response) {
if (response.data.content) {
ezal({
title: "Hint",
body: md.render(response.data.content),
button: "Got it!"
});
} else {
ezal({
title: "Error",
body: "Error loading hint!",
button: "OK"
});
}
});
}
$(document).ready(function () {
$('#hint-add-button').click(function (e) {
$('#hint-edit-modal form').find("input, textarea").val("");
// Markdown Preview
$('#new-hint-edit').on('shown.bs.tab', function (event) {
console.log(event.target.hash);
if (event.target.hash == '#hint-preview') {
console.log(event.target.hash);
var renderer = window.markdownit({
html: true,
});
var editor_value = $('#hint-write textarea').val();
$(event.target.hash).html(renderer.render(editor_value));
}
});
$('#hint-edit-modal').modal();
});
@ -26,7 +75,7 @@ $(document).ready(function () {
e.preventDefault();
var hint_id = $(this).attr('hint-id');
fetch(script_root + '/api/v1/hints/' + hint_id, {
fetch(script_root + '/api/v1/hints/' + hint_id + '?preview=true', {
method: 'GET',
credentials: 'same-origin',
headers: {
@ -41,6 +90,19 @@ $(document).ready(function () {
$('#hint-edit-form input[name=cost]').val(response.data.cost);
$('#hint-edit-form input[name=id]').val(response.data.id);
// Markdown Preview
$('#new-hint-edit').on('shown.bs.tab', function (event) {
console.log(event.target.hash);
if (event.target.hash == '#hint-preview') {
console.log(event.target.hash);
var renderer = new markdownit({
html: true,
});
var editor_value = $('#hint-write textarea').val();
$(event.target.hash).html(renderer.render(editor_value));
}
});
$('#hint-edit-modal').modal();
}
});

View File

@ -114,10 +114,12 @@
var CHALLENGE_ID = {{ challenge.id }};
var CHALLENGE_NAME = {{ challenge.name | tojson }};
</script>
<script src="{{ url_for('views.themes', theme='admin', path='js/vendor/markdown-it.min.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/vendor/moment.min.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/vendor/plotly.min.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/multi-modal.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/challenges/challenge.js') }}"></script>
<script src="{{ url_for('views.themes', theme='core', path='js/hints.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/challenges/hints.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/challenges/flags.js') }}"></script>
<script src="{{ url_for('views.themes', theme='admin', path='js/challenges/tags.js') }}"></script>

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from CTFd.models import Hints
from tests.helpers import *
@ -11,6 +12,7 @@ def test_api_hint_get_non_admin():
with login_as_user(app) as client:
r = client.get('/api/v1/hints', json="")
assert r.status_code == 403
assert Hints.query.count() == 0
destroy_ctfd(app)
@ -45,4 +47,44 @@ def test_api_hint_post_admin():
"cost": "1",
"challenge": 1})
assert r.status_code == 200
assert Hints.query.count() == 1
destroy_ctfd(app)
def test_admins_can_preview_hints():
"""Test that admins are able to bypass restrictions and preview hints with ?preview=true"""
app = create_ctfd()
with app.app_context():
gen_challenge(app.db)
gen_hint(app.db, challenge_id=1, cost=100)
client = login_as_user(app, name="admin", password="password")
r = client.get('/api/v1/hints/1')
assert r.status_code == 200
hint = r.get_json()
assert hint.get('content') is None
r = client.get('/api/v1/hints/1?preview=true')
assert r.status_code == 200
hint = r.get_json()
assert hint['data']['content'] == "This is a hint"
destroy_ctfd(app)
def test_users_cannot_preview_hints():
"""Test that users aren't able to preview hints"""
app = create_ctfd()
with app.app_context():
gen_challenge(app.db)
gen_hint(app.db, challenge_id=1, cost=100)
register_user(app)
client = login_as_user(app)
r = client.get('/api/v1/hints/1')
assert r.status_code == 200
hint = r.get_json()
assert hint.get('content') is None
r = client.get('/api/v1/hints/1?preview=true')
assert r.status_code == 200
hint = r.get_json()
assert hint['data'].get('content') is None
destroy_ctfd(app)