mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-18 14:34:21 +01:00
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
This commit is contained in:
@@ -3,7 +3,7 @@ from flask_restplus import Namespace, Resource
|
|||||||
from CTFd.models import db, Hints, HintUnlocks
|
from CTFd.models import db, Hints, HintUnlocks
|
||||||
from CTFd.plugins.challenges import get_chal_class
|
from CTFd.plugins.challenges import get_chal_class
|
||||||
from CTFd.utils.dates import ctf_ended
|
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.schemas.hints import HintSchema
|
||||||
from CTFd.utils.decorators import (
|
from CTFd.utils.decorators import (
|
||||||
during_ctf_time_only,
|
during_ctf_time_only,
|
||||||
@@ -75,6 +75,10 @@ class Hint(Resource):
|
|||||||
if unlocked:
|
if unlocked:
|
||||||
view = 'unlocked'
|
view = 'unlocked'
|
||||||
|
|
||||||
|
if is_admin():
|
||||||
|
if request.args.get('preview', False):
|
||||||
|
view = 'admin'
|
||||||
|
|
||||||
response = HintSchema(view=view).dump(hint)
|
response = HintSchema(view=view).dump(hint)
|
||||||
|
|
||||||
if response.errors:
|
if response.errors:
|
||||||
|
|||||||
@@ -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 () {
|
$(document).ready(function () {
|
||||||
$('#hint-add-button').click(function (e) {
|
$('#hint-add-button').click(function (e) {
|
||||||
$('#hint-edit-modal form').find("input, textarea").val("");
|
$('#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();
|
$('#hint-edit-modal').modal();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,7 +75,7 @@ $(document).ready(function () {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var hint_id = $(this).attr('hint-id');
|
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',
|
method: 'GET',
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -41,6 +90,19 @@ $(document).ready(function () {
|
|||||||
$('#hint-edit-form input[name=cost]').val(response.data.cost);
|
$('#hint-edit-form input[name=cost]').val(response.data.cost);
|
||||||
$('#hint-edit-form input[name=id]').val(response.data.id);
|
$('#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();
|
$('#hint-edit-modal').modal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -114,10 +114,12 @@
|
|||||||
var CHALLENGE_ID = {{ challenge.id }};
|
var CHALLENGE_ID = {{ challenge.id }};
|
||||||
var CHALLENGE_NAME = {{ challenge.name | tojson }};
|
var CHALLENGE_NAME = {{ challenge.name | tojson }};
|
||||||
</script>
|
</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/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/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/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='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/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/flags.js') }}"></script>
|
||||||
<script src="{{ url_for('views.themes', theme='admin', path='js/challenges/tags.js') }}"></script>
|
<script src="{{ url_for('views.themes', theme='admin', path='js/challenges/tags.js') }}"></script>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from CTFd.models import Hints
|
||||||
from tests.helpers import *
|
from tests.helpers import *
|
||||||
|
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ def test_api_hint_get_non_admin():
|
|||||||
with login_as_user(app) as client:
|
with login_as_user(app) as client:
|
||||||
r = client.get('/api/v1/hints', json="")
|
r = client.get('/api/v1/hints', json="")
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
assert Hints.query.count() == 0
|
||||||
destroy_ctfd(app)
|
destroy_ctfd(app)
|
||||||
|
|
||||||
|
|
||||||
@@ -45,4 +47,44 @@ def test_api_hint_post_admin():
|
|||||||
"cost": "1",
|
"cost": "1",
|
||||||
"challenge": 1})
|
"challenge": 1})
|
||||||
assert r.status_code == 200
|
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)
|
destroy_ctfd(app)
|
||||||
|
|||||||
Reference in New Issue
Block a user