This commit is contained in:
Ilyastarcek
2025-11-07 15:57:27 +03:00
parent 1aff196155
commit e9cf63c1fb
14 changed files with 10232 additions and 10232 deletions

View File

@@ -11,7 +11,7 @@ services:
# - security_net # - security_net
restart: "always" restart: "always"
ports: ports:
- "${FARM_PORT}:8000" - "3333:8000"
postgres: postgres:
image: postgres:18 image: postgres:18

View File

@@ -6,4 +6,4 @@ WORKDIR /app
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
CMD ["./start_server.sh"] ENTRYPOINT ["/app/start_server.sh"]

View File

@@ -27,7 +27,7 @@ def post_flags():
db = database.get() db = database.get()
cursor = db.cursor() cursor = db.cursor()
cursor.executemany("INSERT OR IGNORE INTO flags (flag, sploit, team, time, status) " cursor.executemany("INSERT INTO flags (flag, sploit, team, time, status) "
"VALUES (%s, %s, %s, %s, %s)", rows) "VALUES (%s, %s, %s, %s, %s)", rows)
db.commit() db.commit()

View File

@@ -1,83 +1,83 @@
import socket import socket
from __init__ import app from __init__ import app
from models import FlagStatus, SubmitResult from models import FlagStatus, SubmitResult
RESPONSES = { RESPONSES = {
FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up', FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up',
'no such flag'], 'no such flag'],
FlagStatus.ACCEPTED: ['accepted', 'congrat'], FlagStatus.ACCEPTED: ['accepted', 'congrat'],
FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own', FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own',
'too old', 'not in database', 'already submitted', 'invalid flag', 'too old', 'not in database', 'already submitted', 'invalid flag',
'self', 'invalid', 'already_submitted', 'team_not_found', 'too_old', 'stolen'], 'self', 'invalid', 'already_submitted', 'team_not_found', 'too_old', 'stolen'],
} }
READ_TIMEOUT = 5 READ_TIMEOUT = 5
APPEND_TIMEOUT = 0.05 APPEND_TIMEOUT = 0.05
BUFSIZE = 4096 BUFSIZE = 4096
def recvall(sock): def recvall(sock):
sock.settimeout(READ_TIMEOUT) sock.settimeout(READ_TIMEOUT)
chunks = [sock.recv(BUFSIZE)] chunks = [sock.recv(BUFSIZE)]
sock.settimeout(APPEND_TIMEOUT) sock.settimeout(APPEND_TIMEOUT)
while True: while True:
try: try:
chunk = sock.recv(BUFSIZE) chunk = sock.recv(BUFSIZE)
if not chunk: if not chunk:
break break
chunks.append(chunk) chunks.append(chunk)
except socket.timeout: except socket.timeout:
break break
sock.settimeout(READ_TIMEOUT) sock.settimeout(READ_TIMEOUT)
return b''.join(chunks) return b''.join(chunks)
def submit_flags(flags, config): def submit_flags(flags, config):
try: try:
sock = socket.create_connection((config['SYSTEM_HOST'], config['SYSTEM_PORT']), sock = socket.create_connection((config['SYSTEM_HOST'], config['SYSTEM_PORT']),
READ_TIMEOUT) READ_TIMEOUT)
except (socket.error, ConnectionRefusedError) as e: except (socket.error, ConnectionRefusedError) as e:
app.logger.error(f"Failed to connect to checksystem: {e}") app.logger.error(f"Failed to connect to checksystem: {e}")
# Return all flags as QUEUED since we couldn't submit them # Return all flags as QUEUED since we couldn't submit them
for item in flags: for item in flags:
yield SubmitResult(item.flag, FlagStatus.QUEUED, "Connection failed") yield SubmitResult(item.flag, FlagStatus.QUEUED, "Connection failed")
return return
try: try:
greeting = recvall(sock) greeting = recvall(sock)
if b'Welcome' not in greeting: if b'Welcome' not in greeting:
raise Exception('Checksystem does not greet us: {}'.format(greeting)) raise Exception('Checksystem does not greet us: {}'.format(greeting))
sock.sendall(config['TEAM_TOKEN'].encode() + b'\n') sock.sendall(config['TEAM_TOKEN'].encode() + b'\n')
invite = recvall(sock) invite = recvall(sock)
if b'enter your flags' not in invite: if b'enter your flags' not in invite:
raise Exception('Team token seems to be invalid: {}'.format(invite)) raise Exception('Team token seems to be invalid: {}'.format(invite))
unknown_responses = set() unknown_responses = set()
for item in flags: for item in flags:
sock.sendall(item.flag.encode() + b'\n') sock.sendall(item.flag.encode() + b'\n')
response = recvall(sock).decode().strip() response = recvall(sock).decode().strip()
if response: if response:
response = response.splitlines()[0] response = response.splitlines()[0]
response = response.replace('[{}] '.format(item.flag), '') response = response.replace('[{}] '.format(item.flag), '')
response_lower = response.lower() response_lower = response.lower()
for status, substrings in RESPONSES.items(): for status, substrings in RESPONSES.items():
if any(s in response_lower for s in substrings): if any(s in response_lower for s in substrings):
found_status = status found_status = status
break break
else: else:
found_status = FlagStatus.QUEUED found_status = FlagStatus.QUEUED
if response not in unknown_responses: if response not in unknown_responses:
unknown_responses.add(response) unknown_responses.add(response)
app.logger.warning('Unknown checksystem response (flag will be resent): %s', response) app.logger.warning('Unknown checksystem response (flag will be resent): %s', response)
yield SubmitResult(item.flag, found_status, response) yield SubmitResult(item.flag, found_status, response)
finally: finally:
sock.close() sock.close()

View File

@@ -1,76 +1,76 @@
# Based on https://gist.github.com/xmikasax/90a0ce5736a4274e46b9958f836951e7 # Based on https://gist.github.com/xmikasax/90a0ce5736a4274e46b9958f836951e7
import socket import socket
from __init__ import app from __init__ import app
from models import FlagStatus, SubmitResult from models import FlagStatus, SubmitResult
RESPONSES = { RESPONSES = {
FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up', FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up',
'no such flag'], 'no such flag'],
FlagStatus.ACCEPTED: ['accepted', 'congrat'], FlagStatus.ACCEPTED: ['accepted', 'congrat'],
FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own', FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own',
'too old', 'not in database', 'already submitted', 'invalid flag', 'too old', 'not in database', 'already submitted', 'invalid flag',
'self', 'invalid', 'already_submitted', 'team_not_found', 'too_old', 'stolen'], 'self', 'invalid', 'already_submitted', 'team_not_found', 'too_old', 'stolen'],
} }
READ_TIMEOUT = 5 READ_TIMEOUT = 5
APPEND_TIMEOUT = 0.05 APPEND_TIMEOUT = 0.05
BUFSIZE = 4096 BUFSIZE = 4096
def recvall(sock): def recvall(sock):
sock.settimeout(READ_TIMEOUT) sock.settimeout(READ_TIMEOUT)
chunks = [sock.recv(BUFSIZE)] chunks = [sock.recv(BUFSIZE)]
sock.settimeout(APPEND_TIMEOUT) sock.settimeout(APPEND_TIMEOUT)
while True: while True:
try: try:
chunk = sock.recv(BUFSIZE) chunk = sock.recv(BUFSIZE)
if not chunk: if not chunk:
break break
chunks.append(chunk) chunks.append(chunk)
except socket.timeout: except socket.timeout:
break break
sock.settimeout(READ_TIMEOUT) sock.settimeout(READ_TIMEOUT)
return b''.join(chunks) return b''.join(chunks)
def submit_flags(flags, config): def submit_flags(flags, config):
sock = socket.create_connection((config['SYSTEM_HOST'], config['SYSTEM_PORT']), sock = socket.create_connection((config['SYSTEM_HOST'], config['SYSTEM_PORT']),
READ_TIMEOUT) READ_TIMEOUT)
greeting = recvall(sock) greeting = recvall(sock)
if b'Welcome' not in greeting: if b'Welcome' not in greeting:
raise Exception('Checksystem does not greet us: {}'.format(greeting)) raise Exception('Checksystem does not greet us: {}'.format(greeting))
sock.sendall(config['TEAM_TOKEN'].encode() + b'\n') sock.sendall(config['TEAM_TOKEN'].encode() + b'\n')
invite = recvall(sock) invite = recvall(sock)
if b'enter your flags' not in invite: if b'enter your flags' not in invite:
raise Exception('Team token seems to be invalid: {}'.format(invite)) raise Exception('Team token seems to be invalid: {}'.format(invite))
unknown_responses = set() unknown_responses = set()
for item in flags: for item in flags:
sock.sendall(item.flag.encode() + b'\n') sock.sendall(item.flag.encode() + b'\n')
response = recvall(sock).decode().strip() response = recvall(sock).decode().strip()
if response: if response:
response = response.splitlines()[0] response = response.splitlines()[0]
response = response.replace('[{}] '.format(item.flag), '') response = response.replace('[{}] '.format(item.flag), '')
response_lower = response.lower() response_lower = response.lower()
for status, substrings in RESPONSES.items(): for status, substrings in RESPONSES.items():
if any(s in response_lower for s in substrings): if any(s in response_lower for s in substrings):
found_status = status found_status = status
break break
else: else:
found_status = FlagStatus.QUEUED found_status = FlagStatus.QUEUED
if response not in unknown_responses: if response not in unknown_responses:
unknown_responses.add(response) unknown_responses.add(response)
app.logger.warning('Unknown checksystem response (flag will be resent): %s', response) app.logger.warning('Unknown checksystem response (flag will be resent): %s', response)
yield SubmitResult(item.flag, found_status, response) yield SubmitResult(item.flag, found_status, response)
sock.close() sock.close()

View File

@@ -1,46 +1,46 @@
import requests import requests
from __init__ import app from __init__ import app
from models import FlagStatus, SubmitResult from models import FlagStatus, SubmitResult
RESPONSES = { RESPONSES = {
FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up', FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up',
'no such flag'], 'no such flag'],
FlagStatus.ACCEPTED: ['accepted', 'congrat'], FlagStatus.ACCEPTED: ['accepted', 'congrat'],
FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own', FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own',
'too old', 'not in database', 'already submitted', 'invalid flag'], 'too old', 'not in database', 'already submitted', 'invalid flag'],
} }
# The RuCTF checksystem adds a signature to all correct flags. It returns # The RuCTF checksystem adds a signature to all correct flags. It returns
# "invalid flag" verdict if the signature is invalid and "no such flag" verdict if # "invalid flag" verdict if the signature is invalid and "no such flag" verdict if
# the signature is correct but the flag was not found in the checksystem database. # the signature is correct but the flag was not found in the checksystem database.
# #
# The latter situation happens if a checker puts the flag to the service before putting it # The latter situation happens if a checker puts the flag to the service before putting it
# to the checksystem database. We should resent the flag later in this case. # to the checksystem database. We should resent the flag later in this case.
TIMEOUT = 5 TIMEOUT = 5
def submit_flags(flags, config): def submit_flags(flags, config):
r = requests.put(config['SYSTEM_URL'], r = requests.put(config['SYSTEM_URL'],
headers={'X-Team-Token': config['SYSTEM_TOKEN']}, headers={'X-Team-Token': config['SYSTEM_TOKEN']},
json=[item.flag for item in flags], timeout=TIMEOUT) json=[item.flag for item in flags], timeout=TIMEOUT)
unknown_responses = set() unknown_responses = set()
for item in r.json(): for item in r.json():
response = item['msg'].strip() response = item['msg'].strip()
response = response.replace('[{}] '.format(item['flag']), '') response = response.replace('[{}] '.format(item['flag']), '')
response_lower = response.lower() response_lower = response.lower()
for status, substrings in RESPONSES.items(): for status, substrings in RESPONSES.items():
if any(s in response_lower for s in substrings): if any(s in response_lower for s in substrings):
found_status = status found_status = status
break break
else: else:
found_status = FlagStatus.QUEUED found_status = FlagStatus.QUEUED
if response not in unknown_responses: if response not in unknown_responses:
unknown_responses.add(response) unknown_responses.add(response)
app.logger.warning('Unknown checksystem response (flag will be resent): %s', response) app.logger.warning('Unknown checksystem response (flag will be resent): %s', response)
yield SubmitResult(item['flag'], found_status, response) yield SubmitResult(item['flag'], found_status, response)

View File

@@ -1,74 +1,74 @@
import socket import socket
from __init__ import app from __init__ import app
from models import FlagStatus, SubmitResult from models import FlagStatus, SubmitResult
RESPONSES = { RESPONSES = {
FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up', FlagStatus.QUEUED: ['timeout', 'game not started', 'try again later', 'game over', 'is not up',
'no such flag'], 'no such flag'],
FlagStatus.ACCEPTED: ['accepted', 'congrat'], FlagStatus.ACCEPTED: ['accepted', 'congrat'],
FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own', FlagStatus.REJECTED: ['bad', 'wrong', 'expired', 'unknown', 'your own',
'too old', 'not in database', 'already submitted', 'invalid flag'], 'too old', 'not in database', 'already submitted', 'invalid flag'],
} }
# The RuCTF checksystem adds a signature to all correct flags. It returns # The RuCTF checksystem adds a signature to all correct flags. It returns
# "invalid flag" verdict if the signature is invalid and "no such flag" verdict if # "invalid flag" verdict if the signature is invalid and "no such flag" verdict if
# the signature is correct but the flag was not found in the checksystem database. # the signature is correct but the flag was not found in the checksystem database.
# #
# The latter situation happens if a checker puts the flag to the service before putting it # The latter situation happens if a checker puts the flag to the service before putting it
# to the checksystem database. We should resent the flag later in this case. # to the checksystem database. We should resent the flag later in this case.
READ_TIMEOUT = 5 READ_TIMEOUT = 5
APPEND_TIMEOUT = 0.05 APPEND_TIMEOUT = 0.05
BUFSIZE = 4096 BUFSIZE = 4096
def recvall(sock): def recvall(sock):
sock.settimeout(READ_TIMEOUT) sock.settimeout(READ_TIMEOUT)
chunks = [sock.recv(BUFSIZE)] chunks = [sock.recv(BUFSIZE)]
sock.settimeout(APPEND_TIMEOUT) sock.settimeout(APPEND_TIMEOUT)
while True: while True:
try: try:
chunk = sock.recv(BUFSIZE) chunk = sock.recv(BUFSIZE)
if not chunk: if not chunk:
break break
chunks.append(chunk) chunks.append(chunk)
except socket.timeout: except socket.timeout:
break break
sock.settimeout(READ_TIMEOUT) sock.settimeout(READ_TIMEOUT)
return b''.join(chunks) return b''.join(chunks)
def submit_flags(flags, config): def submit_flags(flags, config):
sock = socket.create_connection((config['SYSTEM_HOST'], config['SYSTEM_PORT']), sock = socket.create_connection((config['SYSTEM_HOST'], config['SYSTEM_PORT']),
READ_TIMEOUT) READ_TIMEOUT)
greeting = recvall(sock) greeting = recvall(sock)
if b'Enter your flags' not in greeting: if b'Enter your flags' not in greeting:
raise Exception('Checksystem does not greet us: {}'.format(greeting)) raise Exception('Checksystem does not greet us: {}'.format(greeting))
unknown_responses = set() unknown_responses = set()
for item in flags: for item in flags:
sock.sendall(item.flag.encode() + b'\n') sock.sendall(item.flag.encode() + b'\n')
response = recvall(sock).decode().strip() response = recvall(sock).decode().strip()
if response: if response:
response = response.splitlines()[0] response = response.splitlines()[0]
response = response.replace('[{}] '.format(item.flag), '') response = response.replace('[{}] '.format(item.flag), '')
response_lower = response.lower() response_lower = response.lower()
for status, substrings in RESPONSES.items(): for status, substrings in RESPONSES.items():
if any(s in response_lower for s in substrings): if any(s in response_lower for s in substrings):
found_status = status found_status = status
break break
else: else:
found_status = FlagStatus.QUEUED found_status = FlagStatus.QUEUED
if response not in unknown_responses: if response not in unknown_responses:
unknown_responses.add(response) unknown_responses.add(response)
app.logger.warning('Unknown checksystem response (flag will be resent): %s', response) app.logger.warning('Unknown checksystem response (flag will be resent): %s', response)
yield SubmitResult(item.flag, found_status, response) yield SubmitResult(item.flag, found_status, response)
sock.close() sock.close()

View File

@@ -1,26 +1,26 @@
from themis.finals.attack.helper import Helper from themis.finals.attack.helper import Helper
from themis.finals.attack.result import Result from themis.finals.attack.result import Result
from models import FlagStatus, SubmitResult from models import FlagStatus, SubmitResult
RESPONSES = { RESPONSES = {
FlagStatus.ACCEPTED: [Result.SUCCESS_FLAG_ACCEPTED], FlagStatus.ACCEPTED: [Result.SUCCESS_FLAG_ACCEPTED],
FlagStatus.REJECTED: [Result.ERROR_FLAG_EXPIRED, Result.ERROR_FLAG_YOURS, FlagStatus.REJECTED: [Result.ERROR_FLAG_EXPIRED, Result.ERROR_FLAG_YOURS,
Result.ERROR_FLAG_SUBMITTED, Result.ERROR_FLAG_NOT_FOUND], Result.ERROR_FLAG_SUBMITTED, Result.ERROR_FLAG_NOT_FOUND],
} }
def submit_flags(flags, config): def submit_flags(flags, config):
h = Helper(config['SYSTEM_HOST']) h = Helper(config['SYSTEM_HOST'])
codes = h.attack(*[item.flag for item in flags]) codes = h.attack(*[item.flag for item in flags])
for item, code in zip(flags, codes): for item, code in zip(flags, codes):
for status, possible_codes in RESPONSES.items(): for status, possible_codes in RESPONSES.items():
if code in possible_codes: if code in possible_codes:
found_status = status found_status = status
break break
else: else:
found_status = FlagStatus.QUEUED found_status = FlagStatus.QUEUED
yield SubmitResult(item.flag, found_status, code.name) yield SubmitResult(item.flag, found_status, code.name)

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,26 @@
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,700italic,400,300,700"); @import url("https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,700italic,400,300,700");
.navbar-brand { .navbar-brand {
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 19px; font-size: 19px;
font-weight: 300; font-weight: 300;
padding: 15px 15px; padding: 15px 15px;
color: #e52250; color: #e52250;
} }
.logo { .logo {
height: 30px; height: 30px;
} }
.table td { .table td {
font-size: 14px; font-size: 14px;
padding: 0.65rem 0.75rem; padding: 0.65rem 0.75rem;
} }
textarea { textarea {
resize: none; resize: none;
} }
#text-with-flags { #text-with-flags {
height: 80px; height: 80px;
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,144 +1,144 @@
function padLeft(s, length) { function padLeft(s, length) {
s = s.toString(); s = s.toString();
while (s.length < length) while (s.length < length)
s = '0' + s; s = '0' + s;
return s; return s;
} }
function dateToString(date) { function dateToString(date) {
return padLeft(date.getFullYear(), 4) + '-' + padLeft(date.getMonth() + 1, 2) + '-' + return padLeft(date.getFullYear(), 4) + '-' + padLeft(date.getMonth() + 1, 2) + '-' +
padLeft(date.getDate(), 2) + ' ' + padLeft(date.getDate(), 2) + ' ' +
padLeft(date.getHours(), 2) + ':' + padLeft(date.getMinutes(), 2) + ':' + padLeft(date.getHours(), 2) + ':' + padLeft(date.getMinutes(), 2) + ':' +
padLeft(date.getSeconds(), 2); padLeft(date.getSeconds(), 2);
} }
function escapeHtml(text) { function escapeHtml(text) {
return $('<div>').text(text).html(); return $('<div>').text(text).html();
} }
function generateFlagTableRows(rows) { function generateFlagTableRows(rows) {
var html = ''; var html = '';
rows.forEach(function (item) { rows.forEach(function (item) {
var cells = [ var cells = [
item.sploit, item.sploit,
item.team !== null ? item.team : '', item.team !== null ? item.team : '',
item.flag, item.flag,
dateToString(new Date(item.time * 1000)), dateToString(new Date(item.time * 1000)),
item.status, item.status,
item.checksystem_response !== null ? item.checksystem_response : '' item.checksystem_response !== null ? item.checksystem_response : ''
]; ];
html += '<tr>'; html += '<tr>';
cells.forEach(function (text) { cells.forEach(function (text) {
html += '<td>' + escapeHtml(text) + '</td>'; html += '<td>' + escapeHtml(text) + '</td>';
}); });
html += '</tr>'; html += '</tr>';
}); });
return html; return html;
} }
function generatePaginator(totalCount, rowsPerPage, pageNumber) { function generatePaginator(totalCount, rowsPerPage, pageNumber) {
var totalPages = Math.ceil(totalCount / rowsPerPage); var totalPages = Math.ceil(totalCount / rowsPerPage);
var firstShown = Math.max(1, pageNumber - 3); var firstShown = Math.max(1, pageNumber - 3);
var lastShown = Math.min(totalPages, pageNumber + 3); var lastShown = Math.min(totalPages, pageNumber + 3);
var html = ''; var html = '';
if (firstShown > 1) if (firstShown > 1)
html += '<li class="page-item"><a class="page-link" href="#" data-content="1">«</a></li>'; html += '<li class="page-item"><a class="page-link" href="#" data-content="1">«</a></li>';
for (var i = firstShown; i <= lastShown; i++) { for (var i = firstShown; i <= lastShown; i++) {
var extraClasses = (i === pageNumber ? "active" : ""); var extraClasses = (i === pageNumber ? "active" : "");
html += '<li class="page-item ' + extraClasses + '">' + html += '<li class="page-item ' + extraClasses + '">' +
'<a class="page-link" href="#" data-content="' + i + '">' + i + '</a>' + '<a class="page-link" href="#" data-content="' + i + '">' + i + '</a>' +
'</li>'; '</li>';
} }
if (lastShown < totalPages) if (lastShown < totalPages)
html += '<li class="page-item">' + html += '<li class="page-item">' +
'<a class="page-link" href="#" data-content="' + totalPages + '">»</a>' + '<a class="page-link" href="#" data-content="' + totalPages + '">»</a>' +
'</li>'; '</li>';
return html; return html;
} }
function getPageNumber() { function getPageNumber() {
return parseInt($('#page-number').val()); return parseInt($('#page-number').val());
} }
function setPageNumber(number) { function setPageNumber(number) {
$('#page-number').val(number); $('#page-number').val(number);
} }
var queryInProgress = false; var queryInProgress = false;
function showFlags() { function showFlags() {
if (queryInProgress) if (queryInProgress)
return; return;
queryInProgress = true; queryInProgress = true;
$('.search-results').hide(); $('.search-results').hide();
$('.query-status').html('Loading...').show(); $('.query-status').html('Loading...').show();
$.post('/ui/show_flags', $('#show-flags-form').serialize()) $.post('/ui/show_flags', $('#show-flags-form').serialize())
.done(function (response) { .done(function (response) {
$('.search-results tbody').html(generateFlagTableRows(response.rows)); $('.search-results tbody').html(generateFlagTableRows(response.rows));
$('.search-results .total-count').text(response.total_count); $('.search-results .total-count').text(response.total_count);
$('.search-results .pagination').html(generatePaginator( $('.search-results .pagination').html(generatePaginator(
response.total_count, response.rows_per_page, getPageNumber())); response.total_count, response.rows_per_page, getPageNumber()));
$('.search-results .page-link').click(function (event) { $('.search-results .page-link').click(function (event) {
event.preventDefault(); event.preventDefault();
setPageNumber($(this).data("content")); setPageNumber($(this).data("content"));
showFlags(); showFlags();
}); });
$('.query-status').hide(); $('.query-status').hide();
$('.search-results').show(); $('.search-results').show();
}) })
.fail(function () { .fail(function () {
$('.query-status').html("Failed to load flags from the farm server"); $('.query-status').html("Failed to load flags from the farm server");
}) })
.always(function () { .always(function () {
queryInProgress = false; queryInProgress = false;
}); });
} }
function postFlagsManual() { function postFlagsManual() {
if (queryInProgress) if (queryInProgress)
return; return;
queryInProgress = true; queryInProgress = true;
$.post('/ui/post_flags_manual', $('#post-flags-manual-form').serialize()) $.post('/ui/post_flags_manual', $('#post-flags-manual-form').serialize())
.done(function () { .done(function () {
var sploitSelect = $('#sploit-select'); var sploitSelect = $('#sploit-select');
if ($('#sploit-manual-option').empty()) if ($('#sploit-manual-option').empty())
sploitSelect.append($('<option id="sploit-manual-option">Manual</option>')); sploitSelect.append($('<option id="sploit-manual-option">Manual</option>'));
sploitSelect.val('Manual'); sploitSelect.val('Manual');
$('#team-select, #flag-input, #time-since-input, #time-until-input, ' + $('#team-select, #flag-input, #time-since-input, #time-until-input, ' +
'#status-select, #checksystem-response-input').val(''); '#status-select, #checksystem-response-input').val('');
queryInProgress = false; queryInProgress = false;
showFlags(); showFlags();
}) })
.fail(function () { .fail(function () {
$('.query-status').html("Failed to post flags to the farm server"); $('.query-status').html("Failed to post flags to the farm server");
queryInProgress = false; queryInProgress = false;
}); });
} }
$(function () { $(function () {
showFlags(); showFlags();
$('#show-flags-form').submit(function (event) { $('#show-flags-form').submit(function (event) {
event.preventDefault(); event.preventDefault();
setPageNumber(1); setPageNumber(1);
showFlags(); showFlags();
}); });
$('#post-flags-manual-form').submit(function (event) { $('#post-flags-manual-form').submit(function (event) {
event.preventDefault(); event.preventDefault();
postFlagsManual(); postFlagsManual();
}); });
}); });

View File

@@ -1,48 +1,48 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Login Required</title> <title>Login Required</title>
<style> <style>
body { body {
font-family: sans-serif; font-family: sans-serif;
max-width: 500px; max-width: 500px;
margin: 40px auto; margin: 40px auto;
padding: 20px; padding: 20px;
} }
.login-form { .login-form {
border: 1px solid #ccc; border: 1px solid #ccc;
padding: 20px; padding: 20px;
border-radius: 4px; border-radius: 4px;
} }
input[type="password"] { input[type="password"] {
width: 100%; width: 100%;
padding: 8px; padding: 8px;
margin: 10px 0; margin: 10px 0;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px; border-radius: 4px;
box-sizing: border-box; box-sizing: border-box;
} }
input[type="submit"] { input[type="submit"] {
background-color: #4CAF50; background-color: #4CAF50;
color: white; color: white;
padding: 10px 15px; padding: 10px 15px;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
} }
input[type="submit"]:hover { input[type="submit"]:hover {
background-color: #45a049; background-color: #45a049;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="login-form"> <div class="login-form">
<h2>Добро пожаловать!</h2> <h2>Добро пожаловать!</h2>
<form method="POST"> <form method="POST">
<label for="password">Пароль:</label> <label for="password">Пароль:</label>
<input type="password" id="password" name="password" required> <input type="password" id="password" name="password" required>
<input type="submit" value="Войти"> <input type="submit" value="Войти">
</form> </form>
</div> </div>
</body> </body>
</html> </html>

View File

@@ -1,150 +1,150 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<link rel="icon" href="/static/logo.png"> <link rel="icon" href="/static/logo.png">
<title>Poison Berries Farm - Server</title> <title>Poison Berries Farm - Server</title>
<link href="/static/css/bootswatch-flatly.css" rel="stylesheet"> <link href="/static/css/bootswatch-flatly.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet">
</head> </head>
<body> <body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark py-0"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark py-0">
<img class="logo" src="/static/img/logo.png"> <img class="logo" src="/static/img/logo.png">
<div class="navbar-brand">Poison Berries Farm</div> <div class="navbar-brand">Poison Berries Farm</div>
</nav> </nav>
<div class="container mt-4"> <div class="container mt-4">
<div class="row mb-4"> <div class="row mb-4">
<div class="col-lg-8"> <div class="col-lg-8">
<div class="card border-light"> <div class="card border-light">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">Show Flags</h4> <h4 class="card-title">Show Flags</h4>
<form id="show-flags-form"> <form id="show-flags-form">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-md-4"> <div class="col-md-4">
<label for="sploit-select">Sploit</label> <label for="sploit-select">Sploit</label>
<select class="form-control form-control-sm" id="sploit-select" name="sploit"> <select class="form-control form-control-sm" id="sploit-select" name="sploit">
<option value="">All</option> <option value="">All</option>
{% for item in distinct_values['sploit'] %} {% for item in distinct_values['sploit'] %}
<option>{{ item }}</option> <option>{{ item }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<label for="team-select">Team</label> <label for="team-select">Team</label>
<select class="form-control form-control-sm" id="team-select" name="team"> <select class="form-control form-control-sm" id="team-select" name="team">
<option value="">All</option> <option value="">All</option>
{% for item in distinct_values['team'] %} {% for item in distinct_values['team'] %}
<option>{{ item }}</option> <option>{{ item }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<label for="flag-input"> <label for="flag-input">
Flag Flag
<small class="text-muted ml-2">substring, case-insensitive</small> <small class="text-muted ml-2">substring, case-insensitive</small>
</label> </label>
<input type="text" class="form-control form-control-sm" id="flag-input" name="flag"> <input type="text" class="form-control form-control-sm" id="flag-input" name="flag">
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-md-3"> <div class="col-md-3">
<label for="time-since-input"> <label for="time-since-input">
Since Since
<small class="text-muted ml-2">{{ server_tz_name }}</small> <small class="text-muted ml-2">{{ server_tz_name }}</small>
</label> </label>
<input type="text" class="form-control form-control-sm" id="time-since-input" <input type="text" class="form-control form-control-sm" id="time-since-input"
name="time-since" name="time-since"
placeholder="yyyy-mm-dd hh:mm"> placeholder="yyyy-mm-dd hh:mm">
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<label for="time-until-input"> <label for="time-until-input">
Until Until
<small class="text-muted ml-2">{{ server_tz_name }}</small> <small class="text-muted ml-2">{{ server_tz_name }}</small>
</label> </label>
<input type="text" class="form-control form-control-sm" id="time-until-input" <input type="text" class="form-control form-control-sm" id="time-until-input"
name="time-until" name="time-until"
placeholder="yyyy-mm-dd hh:mm"> placeholder="yyyy-mm-dd hh:mm">
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
<label for="status-select">Status</label> <label for="status-select">Status</label>
<select class="form-control form-control-sm" id="status-select" name="status"> <select class="form-control form-control-sm" id="status-select" name="status">
<option value="">All</option> <option value="">All</option>
{% for item in distinct_values['status'] %} {% for item in distinct_values['status'] %}
<option>{{ item }}</option> <option>{{ item }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<label for="checksystem-response-input"> <label for="checksystem-response-input">
Checksystem response Checksystem response
</label> </label>
<input type="text" class="form-control form-control-sm" id="checksystem-response-input" <input type="text" class="form-control form-control-sm" id="checksystem-response-input"
name="checksystem_response"> name="checksystem_response">
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<button type="submit" class="btn btn-primary btn-sm submit-btn">Show</button> <button type="submit" class="btn btn-primary btn-sm submit-btn">Show</button>
</div> </div>
</div> </div>
<input type="hidden" value="1" id="page-number" name="page-number"> <input type="hidden" value="1" id="page-number" name="page-number">
</form> </form>
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card border-light"> <div class="card border-light">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">Add Flags Manually</h4> <h4 class="card-title">Add Flags Manually</h4>
<form id="post-flags-manual-form"> <form id="post-flags-manual-form">
<label for="text-with-flags"> <label for="text-with-flags">
Text with flags Text with flags
<small class="text-muted ml-2">flag format: {{ flag_format }}</small> <small class="text-muted ml-2">flag format: {{ flag_format }}</small>
</label> </label>
<textarea class="form-control form-control-sm mb-3" id="text-with-flags" name="text"></textarea> <textarea class="form-control form-control-sm mb-3" id="text-with-flags" name="text"></textarea>
<button type="submit" class="btn btn-primary btn-sm">Send</button> <button type="submit" class="btn btn-primary btn-sm">Send</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="mb-3 text-center query-status"></div> <div class="mb-3 text-center query-status"></div>
<div class="search-results" style="display: none;"> <div class="search-results" style="display: none;">
<p>Found <span class="total-count"></span> flags</p> <p>Found <span class="total-count"></span> flags</p>
<ul class="pagination pagination-sm"></ul> <ul class="pagination pagination-sm"></ul>
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<tr class="table-secondary"> <tr class="table-secondary">
<th scope="col">Sploit</th> <th scope="col">Sploit</th>
<th scope="col">Team</th> <th scope="col">Team</th>
<th scope="col">Flag</th> <th scope="col">Flag</th>
<th scope="col">Time</th> <th scope="col">Time</th>
<th scope="col">Status</th> <th scope="col">Status</th>
<th scope="col">Checksystem Response</th> <th scope="col">Checksystem Response</th>
</tr> </tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
</table> </table>
<ul class="pagination pagination-sm"></ul> <ul class="pagination pagination-sm"></ul>
</div> </div>
</div> </div>
<script src="/static/js/jquery.min.js"></script> <script src="/static/js/jquery.min.js"></script>
<script src="/static/js/ui.js"></script> <script src="/static/js/ui.js"></script>
</body> </body>
</html> </html>