mirror of https://github.com/dirtbags/moth.git
Mostly cosmetics
This commit is contained in:
parent
d9d7ddfe53
commit
ec202f23f5
69
ctf.css
69
ctf.css
|
@ -30,6 +30,49 @@ h1:first-child:before {
|
|||
content: "Capture The Flag: ";
|
||||
}
|
||||
|
||||
/*** left side bar ***/
|
||||
|
||||
#navigation {
|
||||
position: fixed;
|
||||
background: #222;
|
||||
opacity: 0.9;
|
||||
top: 80px;
|
||||
left: 0px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#navigation ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#navigation li a {
|
||||
display: block;
|
||||
height: 25px;
|
||||
width: 90px;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
background: inherit;
|
||||
border-right: 4px solid #444;
|
||||
color: #999;
|
||||
text-transform: lowercase;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#navigation li a:hover {
|
||||
color: #f4f4f4;
|
||||
background: #333;
|
||||
border-right: 4px solid #2a2;
|
||||
}
|
||||
|
||||
#navigation li .active {
|
||||
color: #999;
|
||||
background: #333;
|
||||
border-right: 4px solid #444;
|
||||
}
|
||||
|
||||
|
||||
/**** body ****/
|
||||
|
||||
a img {
|
||||
|
@ -64,6 +107,18 @@ th, td {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.4em;
|
||||
margin-bottom: 20px;
|
||||
color: #f4f4f4;
|
||||
}
|
||||
|
||||
/**** special cases ****/
|
||||
|
||||
.wide {
|
||||
max-width: inherit;
|
||||
}
|
||||
|
||||
.scoreboard {
|
||||
background: #222;
|
||||
}
|
||||
|
@ -72,24 +127,20 @@ th, td {
|
|||
height: 400px;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.4em;
|
||||
margin-bottom: 20px;
|
||||
color: #f4f4f4;
|
||||
}
|
||||
|
||||
.solved {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
table.pollster {
|
||||
margin-left: 5em;
|
||||
margin-left: 5em;
|
||||
}
|
||||
|
||||
table.pollster td {
|
||||
padding: 2px 1em 2px 5px;
|
||||
padding: 2px 1em 2px 5px;
|
||||
}
|
||||
|
||||
table.pollster thead {
|
||||
font-weight: bold;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,27 +28,33 @@ if 'home' in os.environ.get('SCRIPT_FILENAME', ''):
|
|||
}
|
||||
else:
|
||||
# An actual installation
|
||||
config = {'global':
|
||||
{'data_dir': '/var/lib/ctf',
|
||||
'base_url': '/',
|
||||
'css_url': '/ctf.css',
|
||||
'disabled_dir': '/var/lib/ctf/disabled',
|
||||
'flags_dir': '/var/lib/ctf/flags',
|
||||
'house_team': 'dirtbags',
|
||||
'passwd': '/var/lib/ctf/passwd',
|
||||
'team_colors': team_colors,
|
||||
'poll_interval': 60,
|
||||
'poll_timeout': 0.5,
|
||||
'heartbeat_dir': '/var/lib/pollster',
|
||||
'poll_dir': '/var/lib/www',
|
||||
},
|
||||
'puzzler':
|
||||
{'dir': '/usr/lib/www/puzzler',
|
||||
'cgi_url': '/puzzler.cgi',
|
||||
'base_url': '/puzzler',
|
||||
'keys_file': '/usr/lib/ctf/puzzler.keys',
|
||||
},
|
||||
}
|
||||
config = {
|
||||
'global':
|
||||
{
|
||||
'data_dir': '/var/lib/ctf',
|
||||
'base_url': '/',
|
||||
'css_url': '/ctf.css',
|
||||
'disabled_dir': '/var/lib/ctf/disabled',
|
||||
'flags_dir': '/var/lib/ctf/flags',
|
||||
'house_team': 'dirtbags',
|
||||
'passwd': '/var/lib/ctf/passwd',
|
||||
'team_colors': team_colors,
|
||||
},
|
||||
'pollster':
|
||||
{
|
||||
'poll_interval': 60,
|
||||
'poll_timeout': 0.5,
|
||||
'heartbeat_dir': '/var/lib/pollster',
|
||||
'results': '/var/lib/pollster/status.html',
|
||||
},
|
||||
'puzzler':
|
||||
{
|
||||
'dir': '/usr/lib/www/puzzler',
|
||||
'cgi_url': '/puzzler.cgi',
|
||||
'base_url': '/puzzler',
|
||||
'keys_file': '/usr/lib/ctf/puzzler.keys',
|
||||
},
|
||||
}
|
||||
|
||||
def get(section, key):
|
||||
return config[section][key]
|
||||
|
@ -71,22 +77,37 @@ def datafile(filename):
|
|||
def url(path):
|
||||
return base_url + path
|
||||
|
||||
def start_html(title):
|
||||
def start_html(title, hdr='', cls=''):
|
||||
ret = []
|
||||
if os.environ.get('GATEWAY_INTERFACE'):
|
||||
print('Content-type: text/html')
|
||||
print()
|
||||
print('''<?xml version="1.0" encoding="UTF-8"?>
|
||||
ret.append('Content-type: text/html')
|
||||
ret.append('')
|
||||
ret.append('''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC
|
||||
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>%s</title>
|
||||
<link rel="stylesheet" href="%s" type="text/css" />
|
||||
<title>%(title)s</title>
|
||||
<link rel="stylesheet" href="%(css)s" type="text/css" />
|
||||
%(hdr)s
|
||||
</head>
|
||||
<body>
|
||||
<h1>%s</h1>
|
||||
''' % (title, css, title))
|
||||
<body class="%(class)s">
|
||||
<h1>%(title)s</h1>
|
||||
<div id="navigation">
|
||||
<ul>
|
||||
<li><a href="%(base)s">Home</a></li>
|
||||
<li><a href="%(base)sintro.html">Intro/Rules</a></li>
|
||||
<li><a href="%(base)spuzzler.cgi">Puzzles</a></li>
|
||||
<li><a href="%(base)sscoresboard.cgi">Scoreboard</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
''' % {'title': title,
|
||||
'css': css,
|
||||
'hdr': hdr,
|
||||
'base': base_url,
|
||||
'class': cls})
|
||||
return '\n'.join(ret)
|
||||
|
||||
def end_html():
|
||||
print('</body></html>')
|
||||
return '</body></html>'
|
||||
|
|
|
@ -66,9 +66,10 @@ def start_html(title):
|
|||
if passwd:
|
||||
c['passwd'] = passwd
|
||||
print(c)
|
||||
config.start_html(title)
|
||||
print(config.start_html(title))
|
||||
|
||||
end_html = config.end_html
|
||||
def end_html():
|
||||
print(config.end_html())
|
||||
|
||||
def safe_join(*args):
|
||||
safe = list(args[:1])
|
||||
|
|
|
@ -7,26 +7,7 @@ import string
|
|||
from . import teams
|
||||
from . import config
|
||||
|
||||
def head(title):
|
||||
return '''<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Team Registration</title>
|
||||
<link rel="stylesheet" href="%s" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>%s</h1>
|
||||
''' % (config.css, title)
|
||||
|
||||
def foot():
|
||||
return '''</body></html>'''
|
||||
|
||||
def main():
|
||||
print('Content-type: text/html')
|
||||
print()
|
||||
|
||||
f = cgi.FieldStorage()
|
||||
|
||||
team = f.getfirst('team', '')
|
||||
|
|
|
@ -15,20 +15,8 @@ def main():
|
|||
|
||||
categories = [(cat, s.cat_points(cat)) for cat in s.categories()]
|
||||
|
||||
print('Content-type: text/html')
|
||||
print('Refresh: 10')
|
||||
print()
|
||||
print('''<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Scoreboard</title>
|
||||
<link rel="stylesheet" href="%sctf.css" type="text/css" />
|
||||
</head>
|
||||
<body style="max-width: inherit;">
|
||||
<h1>Scoreboard</h1>
|
||||
''' % config.base_url)
|
||||
print(config.start_html('Scoreboard', cls='wide'))
|
||||
print('<table class="scoreboard">')
|
||||
print('<tr>')
|
||||
print('<th>Overall</th>')
|
||||
|
@ -71,9 +59,8 @@ def main():
|
|||
<p class="histogram">
|
||||
<img src="histogram.png" alt="scores over time" />
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>''')
|
||||
''')
|
||||
print(config.end_html())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
7
ctfd.py
7
ctfd.py
|
@ -24,9 +24,6 @@ def reap():
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
def sigchld(signum, frame):
|
||||
do_reap = True
|
||||
|
||||
def main():
|
||||
p = optparse.OptionParser()
|
||||
p.add_option('-p', '--genpass', dest='cat', default=None,
|
||||
|
@ -39,13 +36,11 @@ def main():
|
|||
pointsrv = pointsd.start()
|
||||
flagsrv = flagd.start()
|
||||
|
||||
signal.signal(signal.SIGCHLD, sigchld)
|
||||
s = pointsrv.store
|
||||
slen = 0
|
||||
while True:
|
||||
if do_reap:
|
||||
reap()
|
||||
asyncore.loop(timeout=30, use_poll=True, count=1)
|
||||
reap()
|
||||
if len(s) > slen:
|
||||
slen = len(s)
|
||||
chart(s)
|
||||
|
|
76
mkpuzzles.py
76
mkpuzzles.py
|
@ -17,6 +17,37 @@ opts, args = p.parse_args()
|
|||
|
||||
keys = []
|
||||
|
||||
js = '''
|
||||
<script type="text/javascript">
|
||||
function readCookie(key) {
|
||||
var s = key + '=';
|
||||
var toks = document.cookie.split(';');
|
||||
for (var i = 0; i < toks.length; i++) {
|
||||
var tok = toks[i];
|
||||
while (tok.charAt(0) == ' ') {
|
||||
tok = tok.substring(1, tok.length);
|
||||
}
|
||||
if (tok.indexOf(s) == 0) {
|
||||
return tok.substring(s.length, tok.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTeamInfo() {
|
||||
team = readCookie('team');
|
||||
passwd = readCookie('passwd');
|
||||
if (team != null) {
|
||||
document.getElementById("form").t.value = team;
|
||||
}
|
||||
if (passwd != null) {
|
||||
document.getElementById("form").w.value = passwd;
|
||||
}
|
||||
}
|
||||
window.onload = getTeamInfo;
|
||||
</script>
|
||||
'''
|
||||
|
||||
for cat in os.listdir(opts.puzzles):
|
||||
dirname = os.path.join(opts.puzzles, cat)
|
||||
for points in os.listdir(dirname):
|
||||
|
@ -43,47 +74,7 @@ for cat in os.listdir(opts.puzzles):
|
|||
|
||||
title = '%s for %s points' % (cat, points)
|
||||
f = open(os.path.join(outdir, 'index.html'), 'w', encoding='utf-8')
|
||||
f.write('''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC
|
||||
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>%(title)s</title>
|
||||
<link rel="stylesheet" href="%(css)s" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
function readCookie(key) {
|
||||
var s = key + '=';
|
||||
var toks = document.cookie.split(';');
|
||||
for (var i = 0; i < toks.length; i++) {
|
||||
var tok = toks[i];
|
||||
while (tok.charAt(0) == ' ') {
|
||||
tok = tok.substring(1, tok.length);
|
||||
}
|
||||
if (tok.indexOf(s) == 0) {
|
||||
return tok.substring(s.length, tok.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTeamInfo() {
|
||||
team = readCookie('team');
|
||||
passwd = readCookie('passwd');
|
||||
if (team != null) {
|
||||
document.getElementById("form").t.value = team;
|
||||
}
|
||||
if (passwd != null) {
|
||||
document.getElementById("form").w.value = passwd;
|
||||
}
|
||||
}
|
||||
window.onload = getTeamInfo;
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>%(title)s</h1>
|
||||
''' % {'title': title,
|
||||
'css': config.css})
|
||||
f.write(config.start_html(title, js))
|
||||
if readme:
|
||||
f.write('<div class="readme">%s</div>\n' % readme)
|
||||
if files:
|
||||
|
@ -105,11 +96,10 @@ for cat in os.listdir(opts.puzzles):
|
|||
<input type="submit" />
|
||||
</fieldset>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
''' % {'cgi': config.get('puzzler', 'cgi_url'),
|
||||
'cat': cat,
|
||||
'points': points})
|
||||
f.write(config.end_html())
|
||||
|
||||
f = open(opts.keyfile, 'w', encoding='utf-8')
|
||||
for key in keys:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#! /bin/sh
|
||||
|
||||
case "$REMOTEADDR" in
|
||||
10.0.0.[2-254])
|
||||
touch /var/lib/pollster/$REMOTEADDR
|
||||
ip=$(echo $UDPREMOTEADDR | cut -d: -f1)
|
||||
case "$ip" in
|
||||
10.0.0.*)
|
||||
touch /var/lib/pollster/$ip
|
||||
;;
|
||||
esac
|
||||
|
||||
echo 'Hello.'
|
||||
|
|
|
@ -13,10 +13,10 @@ from ctf import config
|
|||
from ctf import pointscli
|
||||
|
||||
DEBUG = False
|
||||
POLL_INTERVAL = config.get('poll_interval')
|
||||
IP_DIR = config.get('heartbeat_dir')
|
||||
REPORT_PATH = config.get('poll_dir')
|
||||
SOCK_TIMEOUT = config.get('poll_timeout')
|
||||
POLL_INTERVAL = config.get('pollster', 'poll_interval')
|
||||
IP_DIR = config.get('pollster', 'heartbeat_dir')
|
||||
REPORT_PATH = config.get('pollster', 'results')
|
||||
SOCK_TIMEOUT = config.get('pollster', 'poll_timeout')
|
||||
|
||||
class PointSubmitter(threading.Thread):
|
||||
''' Pulls point allocations from the queue and submits them. '''
|
||||
|
@ -184,16 +184,9 @@ while True:
|
|||
out = open(REPORT_PATH, 'w')
|
||||
except Exception as e:
|
||||
out = None
|
||||
pass
|
||||
|
||||
if out is not None:
|
||||
out.write('<html>\n<head>\n')
|
||||
out.write('<title>Pollster Results</title>\n')
|
||||
out.write('<link rel="stylesheet" href="ctf.css" type="text/css" media="all" />\n')
|
||||
out.write('</head><body>\n<h1>Polling Results</h1>\n')
|
||||
|
||||
out.write(config.start_html('Team Service Availability'))
|
||||
for ip in ips:
|
||||
|
||||
# check file name format is ip
|
||||
if ip_re.match(ip) is None:
|
||||
continue
|
||||
|
@ -240,8 +233,7 @@ while True:
|
|||
sleep_time = POLL_INTERVAL - exec_time
|
||||
|
||||
if out is not None:
|
||||
out.write('<p><b>Next poll in: %ds</b></p>\n' % sleep_time)
|
||||
out.write('</body>\n</html>\n')
|
||||
out.write(config.end_html())
|
||||
out.close()
|
||||
|
||||
# sleep until its time to poll again
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#! /bin/sh
|
||||
|
||||
exec udpsvd 0 9 /usr/sbin/in.heartbeatd
|
||||
exec udpsvd 0 9 envuidgid ctf /usr/sbin/in.heartbeatd
|
||||
|
|
|
@ -14,6 +14,8 @@ MAX_HIST = 30
|
|||
HIST_STEP = 100
|
||||
key = 'tanks:::2bac5e912ff2e1ad559b177eb5aeecca'
|
||||
|
||||
running = True
|
||||
|
||||
class Flagger(asynchat.async_chat):
|
||||
"""Use to connect to flagd and submit the current flag holder."""
|
||||
|
||||
|
@ -31,6 +33,7 @@ class Flagger(asynchat.async_chat):
|
|||
def handle_error(self):
|
||||
# If we lose the connection to flagd, nobody can score any
|
||||
# points. Terminate everything.
|
||||
running = False
|
||||
asyncore.close_all()
|
||||
asynchat.async_chat.handle_error(self)
|
||||
|
||||
|
@ -84,6 +87,8 @@ def main():
|
|||
lastrun = 0
|
||||
while True:
|
||||
asyncore.loop(60, count=1)
|
||||
if not running:
|
||||
break
|
||||
now = time.time()
|
||||
if now - lastrun >= 60:
|
||||
run_tanks(args, turns, flagger)
|
||||
|
|
Loading…
Reference in New Issue