function message_generic($title, $message, $head = true, $foot = true, $exit = true) { if ($head) { head($title); } section_subhead($title); message_inline_blue($message); if ($foot) { foot(); } if ($exit) { exit; } }
$categories = db_query_fetch_all('SELECT * FROM categories ORDER BY title'); if (empty($categories)) { message_generic('Welcome', 'Your CTF is looking a bit empty! Start by adding a category using the menu above.'); } section_subhead('CTF Overview', '<a href="' . CONFIG_SITE_ADMIN_URL . 'visualise">Visualise challenge availability</a>', false); foreach ($categories as $category) { echo ' <h4> ', htmlspecialchars($category['title']), ' <a href="edit_category.php?id=', htmlspecialchars($category['id']), '" class="btn btn-xs btn-primary">Edit category</a> <a href="new_challenge.php?category=', htmlspecialchars($category['id']), '" class="btn btn-xs btn-primary">Add challenge</a> </h4> '; $challenges = db_select_all('challenges', array('id', 'title', 'description', 'exposed', 'available_from', 'available_until', 'points'), array('category' => $category['id']), 'points ASC'); if (empty($challenges)) { message_inline_blue('This category is empty! Use the link above to add a challenge.'); } else { echo ' <table class="table table-striped table-hover"> <thead> <tr> <th>Title</th> <th>Description</th> <th class="center">Points</th> <th class="center">Visibility</th> <th class="center">Manage</th> </tr> </thead> <tbody> '; foreach ($challenges as $challenge) {
cache_end(CONST_CACHE_NAME_CHALLENGE_HINTS . $challenge['id']); } // write out files $files = cache_array_get(CONST_CACHE_NAME_FILES . $challenge['id'], CONFIG_CACHE_TIME_FILES); if (!is_array($files)) { $files = db_select_all('files', array('id', 'title', 'size', 'md5', 'download_key'), array('challenge' => $challenge['id'])); cache_array_save($files, CONST_CACHE_NAME_FILES . $challenge['id']); } if (count($files)) { print_attachments($files); } // only show the hints and flag submission form if we're not already correct and if the challenge hasn't expired if (!$challenge['correct_submission_added'] && $time < $challenge['available_until']) { if ($remaining_submissions) { if ($challenge['num_submissions'] && !$challenge['automark'] && $challenge['marked']) { message_inline_blue('Your submission is awaiting manual marking.'); } echo ' <div class="challenge-submit"> <form method="post" class="form-flag" action="actions/challenges"> <textarea name="flag" type="text" class="flag-input form-control" placeholder="Please enter flag for challenge: ', htmlspecialchars($challenge['title']), '"></textarea> <input type="hidden" name="challenge" value="', htmlspecialchars($challenge['id']), '" /> <input type="hidden" name="action" value="submit_flag" />'; form_xsrf_token(); if (CONFIG_RECAPTCHA_ENABLE_PRIVATE) { display_captcha(); } echo '<button class="btn btn-sm btn-primary flag-submit-button" type="submit" data-countdown="', max($challenge['latest_submission_added'] + $challenge['min_seconds_between_submissions'], 0), '" data-countdown-done="Submit flag">Submit flag</button>'; if (should_print_metadata($challenge)) { echo '<div class="challenge-submit-metadata">'; print_submit_metadata($challenge);
<?php require '../../include/mellivora.inc.php'; enforce_authentication(CONST_USER_CLASS_MODERATOR); head('Site management'); menu_management(); section_subhead('New user type'); message_inline_blue('User types are not required. You can add them if you wish to group contestants and give them separate scoreboards. If not, everyone will be in the same group.'); form_start(CONFIG_SITE_ADMIN_RELPATH . 'actions/new_user_type'); form_input_text('Title'); form_textarea('Description'); form_hidden('action', 'new'); form_button_submit('Create new user type'); form_end(); foot();
<?php require '../../include/mellivora.inc.php'; enforce_authentication(CONST_USER_CLASS_MODERATOR); head('Site management'); menu_management(); section_subhead('New challenge'); form_start(CONFIG_SITE_ADMIN_RELPATH . 'actions/new_challenge'); form_input_text('Title'); form_textarea('Description'); form_textarea('Flag'); form_input_checkbox('Automark', true); form_input_checkbox('Case insensitive'); form_input_text('Points'); form_input_text('Num attempts allowed'); form_input_text('Min seconds between submissions'); $opts = db_query_fetch_all('SELECT * FROM categories ORDER BY title'); form_select($opts, 'Category', 'id', array_get($_GET, 'category'), 'title'); form_input_checkbox('Exposed', true); form_input_text('Available from', date_time()); form_input_text('Available until', date_time()); message_inline_blue('Create and edit challenge to add files.'); form_hidden('action', 'new'); form_button_submit('Create challenge'); form_end(); foot();
<?php require '../../include/mellivora.inc.php'; enforce_authentication(CONFIG_UC_MODERATOR); enforce_instance_auth(); head('Site management'); menu_management(); section_subhead('Test signup rules'); message_inline_blue('Enter an email addess to test.'); form_start(CONFIG_SITE_ADMIN_RELPATH . 'actions/test_restrict_email'); form_input_text('Email'); form_hidden('action', 'test'); form_button_submit('Test'); form_end(); foot();
validate_id($_GET['id']); head('User details'); if (cache_start('user_' . $_GET['id'], CONFIG_CACHE_TIME_USER)) { $user = db_query_fetch_one(' SELECT u.team_name, u.competing, co.country_name, co.country_code FROM users AS u LEFT JOIN countries AS co ON co.id = u.country_id WHERE u.id = :user_id', array('user_id' => $_GET['id'])); section_head(htmlspecialchars($user['team_name']), country_flag_link($user['country_name'], $user['country_code'], true), false); if (!$user['competing']) { message_inline_blue('This user is listed as a non-competitor.'); } $challenges = db_query_fetch_all(' SELECT ca.title, (SELECT SUM(ch.points) FROM challenges AS ch JOIN submissions AS s ON s.challenge = ch.id AND s.user_id = :user_id AND s.correct = 1 WHERE ch.category = ca.id GROUP BY ch.category) AS points, (SELECT SUM(ch.points) FROM challenges AS ch WHERE ch.category = ca.id GROUP BY ch.category) AS category_total FROM categories AS ca ORDER BY ca.title ASC', array('user_id' => $_GET['id'])); $user_total = 0; $ctf_total = 0; foreach ($challenges as $challenge) { echo '<strong>', htmlspecialchars($challenge['title']), '</strong>, ', number_format($challenge['points']), ' / ', number_format($challenge['category_total']), ' (', round($challenge['points'] / max(1, $challenge['category_total']) * 100), '%)'; progress_bar($challenge['points'] / max(1, $challenge['category_total']) * 100); $user_total += $challenge['points']; $ctf_total += $challenge['category_total'];
', lang_get('account_signup_information', array('password_information' => CONFIG_ACCOUNTS_EMAIL_PASSWORD_ON_SIGNUP ? lang_get('email_password_on_signup') : '')), ' </p> <form method="post" id="registerForm" class="form-signin" action="actions/register"> <input name="team_name" type="text" class="form-control" placeholder="Team name" minlength="', CONFIG_MIN_TEAM_NAME_LENGTH, '" maxlength="', CONFIG_MAX_TEAM_NAME_LENGTH, '" required /> <input name="', md5(CONFIG_SITE_NAME . 'USR'), '" type="email" class="form-control" placeholder="Email address" required /> ', !CONFIG_ACCOUNTS_EMAIL_PASSWORD_ON_SIGNUP ? '<input name="' . md5(CONFIG_SITE_NAME . 'PWD') . '" type="password" class="form-control" placeholder="Password" required />' : ''; if (cache_start(CONST_CACHE_NAME_REGISTER, CONFIG_CACHE_TIME_REGISTER)) { $user_types = db_select_all('user_types', array('id', 'title', 'description')); if (!empty($user_types)) { echo '<select name="type" class="form-control"> <option disabled selected>-- Please select team type --</option>'; foreach ($user_types as $user_type) { echo '<option value="', htmlspecialchars($user_type['id']), '">', htmlspecialchars($user_type['title'] . ' - ' . $user_type['description']), '</option>'; } echo '</select>'; } country_select(); cache_end(CONST_CACHE_NAME_REGISTER); } if (CONFIG_RECAPTCHA_ENABLE_PUBLIC) { display_captcha(); } echo ' <input type="hidden" name="action" value="register" /> <button class="btn btn-primary btn-lg" type="submit">Register team</button> </form> '; } else { message_inline_blue('Registration is currently closed, but you can still <a href="interest">register your interest for upcoming events</a>.', false); } foot();
</thead> <tbody> '; foreach ($submissions as $submission) { echo ' <tr> <td> <a href="challenge?id=', htmlspecialchars($submission['challenge_id']), '"> ', htmlspecialchars($submission['title']), ' </a> (', htmlspecialchars($submission['category_title']), ') </td> <td> ', get_position_medal($submission['pos'], true), ' ', time_elapsed($submission['added'], $submission['available_from']), ' ', lang_get('after_release'), ' (', date_time($submission['added']), ') </td> <td>', number_format($submission['points']), '</td> </tr> '; } echo ' </tbody> </table> '; } else { message_inline_blue(lang_get('no_challenges_solved')); } cache_end(CONST_CACHE_NAME_USER . $_GET['id']); } foot();
<?php require '../../include/ctf.inc.php'; enforce_authentication(CONST_USER_CLASS_MODERATOR); head('Site management'); menu_management(); section_subhead('New email signup restriction rule'); message_inline_blue('Add rules to restrict which emails can sign up. Rules in list below are applied top-down. Rules further down on the list override rules above. List is ordered by "priority". A higher "priority" value puts a rule further down the list. Rules are PCRE regex. Example: ^.+@.+$'); form_start(CONFIG_SITE_ADMIN_RELPATH . 'actions/new_restrict_email'); form_input_text('Rule'); form_input_text('Priority'); form_input_checkbox('Whitelist'); form_input_checkbox('Enabled'); form_hidden('action', 'new'); form_button_submit('Create new rule'); form_end(); foot();
<?php require '../include/mellivora.inc.php'; validate_id(array_get($_GET, 'id')); head(lang_get('user_details')); if (cache_start(CONST_CACHE_NAME_USER . $_GET['id'], CONFIG_CACHE_TIME_USER)) { $user = db_query_fetch_one(' SELECT u.team_name, u.competing, co.country_name, co.country_code FROM users AS u LEFT JOIN countries AS co ON co.id = u.country_id WHERE u.id = :user_id', array('user_id' => $_GET['id'])); if (empty($user)) { message_generic(lang_get('sorry'), lang_get('no_user_found'), false); } section_head(htmlspecialchars($user['team_name']), country_flag_link($user['country_name'], $user['country_code'], true), false); if (!$user['competing']) { message_inline_blue(lang_get('non_competing_user')); } print_solved_graph($_GET['id']); print_solved_challenges($_GET['id']); cache_end(CONST_CACHE_NAME_USER . $_GET['id']); } foot();
function print_user_exception_log($user_id, $limit = false) { validate_id($user_id); section_subhead('Exception log', ($limit ? 'Limited to ' . $limit . ' results ' : '') . button_link('Show all for user', 'list_exceptions?user_id=' . $user_id), false); $exceptions = db_query_fetch_all(' SELECT e.id, e.message, e.added, e.added_by, e.trace, INET_NTOA(e.user_ip) AS user_ip, u.team_name FROM exceptions AS e LEFT JOIN users AS u ON u.id = e.added_by WHERE e.added_by = :user_id ORDER BY e.id DESC ' . ($limit ? 'LIMIT ' . $limit : ''), array('user_id' => $user_id)); if (count($exceptions)) { echo ' <table id="hints" class="table table-striped table-hover"> <thead> <tr> <th>Message</th> <th>Added</th> <th>IP</th> <th>Trace</th> </tr> </thead> <tbody> '; foreach ($exceptions as $exception) { echo ' <tr> <td>', htmlspecialchars($exception['message']), '</td> <td>', date_time($exception['added']), '</td> <td><a href="', CONFIG_SITE_ADMIN_URL, 'list_ip_log.php?ip=', htmlspecialchars($exception['user_ip']), '">', htmlspecialchars($exception['user_ip']), '</a></td> <td>', htmlspecialchars($exception['trace']), '</td> </tr> '; } echo ' </tbody> </table> '; } else { message_inline_blue(lang_get('no_exceptions')); } }
<?php require '../../include/mellivora.inc.php'; enforce_authentication(CONST_USER_CLASS_MODERATOR); head('Site management'); menu_management(); if (array_get($_GET, 'bcc') == 'all') { $users = db_select_all('users', array('email')); $bcc = ''; foreach ($users as $user) { $bcc .= $user['email'] . ",\n"; } $bcc = trim($bcc); } section_subhead('New email'); message_inline_blue('Separate receiver emails with a comma and optional whitespace. You can use BBCode. If you do, you must send as HTML email.'); form_start(CONFIG_SITE_ADMIN_RELPATH . 'actions/new_email'); if (isset($bcc)) { form_input_text('To', CONFIG_EMAIL_FROM_EMAIL); form_input_text('CC'); form_textarea('BCC', $bcc); } else { form_input_text('To', isset($_GET['to']) ? $_GET['to'] : ''); form_input_text('CC'); form_input_text('BCC'); } form_input_text('Subject'); form_textarea('Body'); form_input_checkbox('HTML email'); form_hidden('action', 'new'); message_inline_yellow('Important email? Remember to Ctrl+C before attempting to send!');
<?php require '../../include/mellivora.inc.php'; enforce_authentication(CONST_USER_CLASS_MODERATOR); head('Visualise'); menu_management(); section_subhead('Visualise challenge availability', '<a href="' . CONFIG_SITE_ADMIN_URL . '">CTF Overview</a>', false); echo '<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.15.1/vis.min.js"></script>'; echo '<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.15.1/vis.min.css" rel="stylesheet">'; message_inline_blue('Green = available now, Red = unavailable. ' . unichr(CONST_CHAR_CROSS) . ' = not exposed, ' . unichr(CONST_CHAR_CLOCK) . ' = not available because of time constraints, ' . unichr(CONST_CHAR_UPARROW) . ' = relies on challenge which is not yet solved, or is in a category which is not available'); echo '<div id="visualise-competition"></div>'; echo '<script type="text/javascript">'; function is_visible($from, $until) { $now = time(); if ($now > $from && $now < $until) { return true; } return false; } function is_challenge_available($category, $challenge) { return $challenge['exposed'] && is_visible($challenge['available_from'], $challenge['available_until']) && is_category_available($category) && !is_parent_challenge_blocking($challenge); } function is_category_available($category) { return $category['exposed'] && is_visible($category['available_from'], $category['available_until']); } function is_parent_challenge_blocking($challenge) { if (!$challenge['relies_on']) {