mirror of https://github.com/dirtbags/moth.git
Mostly cosmetic changes
This commit is contained in:
parent
f82d78bd6a
commit
da11d73276
5
Makefile
5
Makefile
|
@ -22,13 +22,16 @@ target: $(PYC)
|
||||||
$(INSTALL) ctfd.py $(CTFDIR)
|
$(INSTALL) ctfd.py $(CTFDIR)
|
||||||
|
|
||||||
$(INSTALL) -d $(WWWDIR)
|
$(INSTALL) -d $(WWWDIR)
|
||||||
$(INSTALL) index.html intro.html ctf.css $(WWWDIR)
|
$(INSTALL) index.html intro.html ctf.css grunge.png $(WWWDIR)
|
||||||
$(FAKE) ln -s /var/lib/ctf/histogram.png $(WWWDIR)
|
$(FAKE) ln -s /var/lib/ctf/histogram.png $(WWWDIR)
|
||||||
$(INSTALL) register.cgi scoreboard.cgi puzzler.cgi $(WWWDIR)
|
$(INSTALL) register.cgi scoreboard.cgi puzzler.cgi $(WWWDIR)
|
||||||
|
|
||||||
$(INSTALL) -d $(DESTDIR)/var/service/ctf
|
$(INSTALL) -d $(DESTDIR)/var/service/ctf
|
||||||
$(INSTALL) run.ctfd $(DESTDIR)/var/service/ctf/run
|
$(INSTALL) run.ctfd $(DESTDIR)/var/service/ctf/run
|
||||||
|
|
||||||
|
$(INSTALL) -d $(DESTDIR)/var/service/ctf/log
|
||||||
|
$(INSTALL) run.log.ctfd $(DESTDIR)/var/service/ctf/log/run
|
||||||
|
|
||||||
rm -rf $(WWWDIR)/puzzler
|
rm -rf $(WWWDIR)/puzzler
|
||||||
$(INSTALL) -d $(WWWDIR)/puzzler
|
$(INSTALL) -d $(WWWDIR)/puzzler
|
||||||
./mkpuzzles.py --htmldir=$(WWWDIR)/puzzler --keyfile=$(CTFDIR)/puzzler.keys
|
./mkpuzzles.py --htmldir=$(WWWDIR)/puzzler --keyfile=$(CTFDIR)/puzzler.keys
|
||||||
|
|
17
config.py
17
config.py
|
@ -2,17 +2,25 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
team_colors = ['F0888A', '88BDF0', '00782B', '999900', 'EF9C00',
|
||||||
|
'F4B5B7', 'E2EFFB', '89CA9D', 'FAF519', 'FFE7BB',
|
||||||
|
'BA88F0', '8DCFF4', 'BEDFC4', 'FFFAB2', 'D7D7D7',
|
||||||
|
'C5B9D7', '006189', '8DCB41', 'FFCC00', '898989']
|
||||||
|
|
||||||
if 'home' in os.environ.get('SCRIPT_FILENAME', ''):
|
if 'home' in os.environ.get('SCRIPT_FILENAME', ''):
|
||||||
# We're a CGI running out of someone's home directory
|
# We're a CGI running out of someone's home directory
|
||||||
config = {'global':
|
config = {'global':
|
||||||
{'data_dir': '.',
|
{'data_dir': '.',
|
||||||
'base_url': '.',
|
'base_url': '.',
|
||||||
'css_url': 'ctf.css',
|
'css_url': 'ctf.css',
|
||||||
'diasbled_dir': 'disabled'
|
'diasbled_dir': 'disabled',
|
||||||
|
'flags_dir': 'flags',
|
||||||
|
'house_team': 'dirtbags',
|
||||||
|
'passwd': 'passwd',
|
||||||
|
'team_colors': team_colors,
|
||||||
},
|
},
|
||||||
'puzzler':
|
'puzzler':
|
||||||
{'dir': 'puzzles',
|
{'dir': 'puzzles',
|
||||||
'ignore_dir': 'puzzler.ignore',
|
|
||||||
'cgi_url': 'puzzler.cgi',
|
'cgi_url': 'puzzler.cgi',
|
||||||
'base_url': 'puzzler',
|
'base_url': 'puzzler',
|
||||||
'keys_file': 'puzzler.keys',
|
'keys_file': 'puzzler.keys',
|
||||||
|
@ -25,10 +33,13 @@ else:
|
||||||
'base_url': '/',
|
'base_url': '/',
|
||||||
'css_url': '/ctf.css',
|
'css_url': '/ctf.css',
|
||||||
'disabled_dir': '/var/lib/ctf/disabled',
|
'disabled_dir': '/var/lib/ctf/disabled',
|
||||||
|
'flags_dir': '/var/lib/ctf/flags',
|
||||||
|
'house_team': 'dirtbags',
|
||||||
|
'passwd': '/var/lib/ctf/passwd',
|
||||||
|
'team_colors': team_colors,
|
||||||
},
|
},
|
||||||
'puzzler':
|
'puzzler':
|
||||||
{'dir': '/usr/lib/www/puzzler',
|
{'dir': '/usr/lib/www/puzzler',
|
||||||
'ignore_dir': '/var/lib/ctf/puzzler.ignore',
|
|
||||||
'cgi_url': '/puzzler.cgi',
|
'cgi_url': '/puzzler.cgi',
|
||||||
'base_url': '/puzzler',
|
'base_url': '/puzzler',
|
||||||
'keys_file': '/usr/lib/ctf/puzzler.keys',
|
'keys_file': '/usr/lib/ctf/puzzler.keys',
|
||||||
|
|
17
ctf.css
17
ctf.css
|
@ -1,7 +1,7 @@
|
||||||
/**** document ****/
|
/**** document ****/
|
||||||
|
|
||||||
html {
|
html {
|
||||||
background: #222 url(http://dirtbags.net/images/grunge.png) no-repeat;
|
background: #222 url(grunge.png) repeat-x;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -29,18 +29,24 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
code, pre, .readme {
|
code, pre, .readme {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreboard td {
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
/**** heading ****/
|
/**** heading ****/
|
||||||
|
|
||||||
h1:first-child {
|
h1:first-child {
|
||||||
text-transform: lowercase;
|
text-transform: lowercase;
|
||||||
font-size: 1.6em;
|
font-size: 1.6em;
|
||||||
letter-spacing: -0.1em;
|
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
|
@ -50,6 +56,7 @@ h1:first-child {
|
||||||
|
|
||||||
h1:first-child:before {
|
h1:first-child:before {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
letter-spacing: -0.1em;
|
||||||
content: "Capture The Flag: ";
|
content: "Capture The Flag: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
flagd.py
10
flagd.py
|
@ -7,15 +7,19 @@ import functools
|
||||||
import time
|
import time
|
||||||
import hmac
|
import hmac
|
||||||
import optparse
|
import optparse
|
||||||
|
import os
|
||||||
import points
|
import points
|
||||||
import pointscli
|
import pointscli
|
||||||
import teams
|
import teams
|
||||||
|
import config
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
key = b'My First Shared Secret (tm)'
|
key = b'My First Shared Secret (tm)'
|
||||||
def hexdigest(data):
|
def hexdigest(data):
|
||||||
return hmac.new(key, data).hexdigest()
|
return hmac.new(key, data).hexdigest()
|
||||||
|
|
||||||
|
flags_dir = config.get('global', 'flags_dir')
|
||||||
|
|
||||||
class Submitter(asyncore.dispatcher):
|
class Submitter(asyncore.dispatcher):
|
||||||
def __init__(self, host='localhost', port=6667):
|
def __init__(self, host='localhost', port=6667):
|
||||||
asyncore.dispatcher.__init__(self)
|
asyncore.dispatcher.__init__(self)
|
||||||
|
@ -110,8 +114,10 @@ class FlagServer(asynchat.async_chat):
|
||||||
|
|
||||||
def set_flag(self, team):
|
def set_flag(self, team):
|
||||||
self.flag = team
|
self.flag = team
|
||||||
if self.cat:
|
self.submitter.set_flag(self.cat, team)
|
||||||
self.submitter.set_flag(self.cat, team)
|
f = open(os.path.join(flags_dir, self.cat), 'w')
|
||||||
|
if team:
|
||||||
|
f.write(team)
|
||||||
|
|
||||||
def found_terminator(self):
|
def found_terminator(self):
|
||||||
data = b''.join(self.inbuf)
|
data = b''.join(self.inbuf)
|
||||||
|
|
8
game.py
8
game.py
|
@ -59,9 +59,11 @@ class Flagger(asynchat.async_chat):
|
||||||
asynchat.async_chat.handle_error(self)
|
asynchat.async_chat.handle_error(self)
|
||||||
|
|
||||||
def set_flag(self, team):
|
def set_flag(self, team):
|
||||||
if not team:
|
if team:
|
||||||
team = 'dirtbags'
|
eteam = team.encode('utf-8')
|
||||||
self.push(team.encode('utf-8') + b'\n')
|
else:
|
||||||
|
eteam = b''
|
||||||
|
self.push(eteam + b'\n')
|
||||||
self.flag = team
|
self.flag = team
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
|
@ -4,6 +4,7 @@ import points
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import teams
|
||||||
import config
|
import config
|
||||||
|
|
||||||
pngout = config.datafile('histogram.png')
|
pngout = config.datafile('histogram.png')
|
||||||
|
@ -16,8 +17,7 @@ def main(s=None):
|
||||||
s = points.Storage()
|
s = points.Storage()
|
||||||
|
|
||||||
plotparts = []
|
plotparts = []
|
||||||
teams = s.teams()
|
teams = s.teams
|
||||||
teamcolors = points.colors(teams)
|
|
||||||
|
|
||||||
catscores = {}
|
catscores = {}
|
||||||
for cat in s.categories():
|
for cat in s.categories():
|
||||||
|
@ -27,7 +27,7 @@ def main(s=None):
|
||||||
fn = scoresfile.name
|
fn = scoresfile.name
|
||||||
i = 2
|
i = 2
|
||||||
for team in teams:
|
for team in teams:
|
||||||
plotparts.append('"%s" using 1:%d with lines linewidth 2 linetype rgb "#%s"' % (fn, i, teamcolors[team]))
|
plotparts.append('"%s" using 1:%d with lines linewidth 2 linetype rgb "#%s"' % (fn, i, teams.color(team)))
|
||||||
scores[team] = 0
|
scores[team] = 0
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
58
intro.html
58
intro.html
|
@ -10,7 +10,7 @@
|
||||||
<h1>Introduction</h1>
|
<h1>Introduction</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Welcome to Capture The Flag, blah blah blah.
|
Welcome to Capture The Flag.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>What This Is</h2>
|
<h2>What This Is</h2>
|
||||||
|
@ -35,7 +35,9 @@
|
||||||
<h3>Important Rules</h3>
|
<h3>Important Rules</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The contest network is 10.<i>x</i>.<i>x</i>.<i>x</i>. <b>Do
|
<li>The contest network is 10.<i>x</i>.<i>x</i>.<i>x</i>. <b>Do
|
||||||
not attack machines outside the contest network</b>.</li>
|
not attack machines outside the contest network</b>. All
|
||||||
|
federal, state, and school laws still apply to the outside
|
||||||
|
network.</li>
|
||||||
<li>If the "outside network" requires you to plug into a different
|
<li>If the "outside network" requires you to plug into a different
|
||||||
switch, do not connect any machine that has been on the contest
|
switch, do not connect any machine that has been on the contest
|
||||||
network.</li>
|
network.</li>
|
||||||
|
@ -52,10 +54,49 @@
|
||||||
<li>If IRC is up, you should use it to communicate with the
|
<li>If IRC is up, you should use it to communicate with the
|
||||||
contest staff. Staff will have operator status in #ctf.</li>
|
contest staff. Staff will have operator status in #ctf.</li>
|
||||||
<li>If you think something is wrong with the game, you are
|
<li>If you think something is wrong with the game, you are
|
||||||
expected to demonstrate the problem and explain why you think
|
expected to demonstrate the problem and explain what you think
|
||||||
it's a problem.</li>
|
is the correct behavior.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h2>Scoring</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The contest is made up of multiple <em>categories</em>. Each
|
||||||
|
category is worth one point toward the total score; the percentage
|
||||||
|
of the total points held by your team is the percentage of one
|
||||||
|
point your team has for that category. The team that has 30% of
|
||||||
|
the points in each of five categories has 1.5 points, whereas the
|
||||||
|
team that has 80% of the points in only one category has 0.8
|
||||||
|
points.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There are two kinds of categories: <em>flags</em>,
|
||||||
|
and <em>puzzles</em>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Flags</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Flag categories are challenges with a notion of a <em>winner</em>
|
||||||
|
or <em>service availability</em>. In these categories, the
|
||||||
|
flag-holder (the winner, or each team with a running service)
|
||||||
|
makes 1 point per minute for as long as they hold the flag. If
|
||||||
|
there is a single flag-holder, and the flag changes hands, a point
|
||||||
|
is awarded to the new winner at the moment the flag moves.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Puzzles</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Most of the categories come in the form of
|
||||||
|
multiple <em>puzzles</em>: for each puzzle presented, a key
|
||||||
|
(answer) must be found to recieve the amount of points that puzzle
|
||||||
|
is worth. Any team may answer any puzzle question at any time. A
|
||||||
|
new puzzle is revealed when a team correctly answers the
|
||||||
|
highest-valued puzzle in that category.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2>Hints</h2>
|
<h2>Hints</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -63,15 +104,16 @@
|
||||||
points, though. For puzzles, you will lose ¼ of the points for
|
points, though. For puzzles, you will lose ¼ of the points for
|
||||||
that puzzle <em>even if you never solve the puzzle</em>. For
|
that puzzle <em>even if you never solve the puzzle</em>. For
|
||||||
other events, the staff member will decide how many points it will
|
other events, the staff member will decide how many points it will
|
||||||
cost. You can try to bribe us or otherwise fanagle information
|
cost. You can try to bribe or otherwise fanagle information out
|
||||||
out of us, or other contestants. <em>It's a hacking contest.</em>
|
of us or other contestants. <em>It's a hacking contest.</em>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>About Us</h2>
|
<h2>About Us</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
We are the <a href="http://dirtbags.net/">dirtbags</a>. You might
|
We are the <a href="http://dirtbags.net/">dirtbags</a>. People
|
||||||
be better at this than we are, but you're not running the contest.
|
pay us money to do the sorts of things you'll be doing in this
|
||||||
|
contest.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
29
points.py
29
points.py
|
@ -93,7 +93,7 @@ class Storage:
|
||||||
def __init__(self, fn=None):
|
def __init__(self, fn=None):
|
||||||
if not fn:
|
if not fn:
|
||||||
fn = config.datafile('scores.dat')
|
fn = config.datafile('scores.dat')
|
||||||
self.points_by_team = {}
|
self.teams = set()
|
||||||
self.points_by_cat = {}
|
self.points_by_cat = {}
|
||||||
self.points_by_cat_team = {}
|
self.points_by_cat_team = {}
|
||||||
self.log = []
|
self.log = []
|
||||||
|
@ -128,7 +128,7 @@ class Storage:
|
||||||
def add(self, req, write=True):
|
def add(self, req, write=True):
|
||||||
when, cat, team, score = req
|
when, cat, team, score = req
|
||||||
|
|
||||||
incdict(self.points_by_team, team, score)
|
self.teams.add(team)
|
||||||
incdict(self.points_by_cat, cat, score)
|
incdict(self.points_by_cat, cat, score)
|
||||||
incdict(self.points_by_cat_team, (cat, team), score)
|
incdict(self.points_by_cat_team, (cat, team), score)
|
||||||
self.log.append(req)
|
self.log.append(req)
|
||||||
|
@ -146,31 +146,23 @@ class Storage:
|
||||||
def categories(self):
|
def categories(self):
|
||||||
return sorted(self.points_by_cat)
|
return sorted(self.points_by_cat)
|
||||||
|
|
||||||
def teams(self):
|
def get_teams(self):
|
||||||
return sorted(self.points_by_team)
|
return sorted(self.teams)
|
||||||
|
|
||||||
def cat_points(self, cat):
|
def cat_points(self, cat):
|
||||||
return self.points_by_cat.get(cat, 0)
|
return self.points_by_cat.get(cat, 0)
|
||||||
|
|
||||||
def team_points(self, team):
|
def team_points(self, team):
|
||||||
return self.points_by_team.get(team, 0)
|
points = 0
|
||||||
|
for cat, tot in self.points_by_cat.items():
|
||||||
|
team_points = self.team_points_in_cat(cat, team)
|
||||||
|
points += team_points / float(tot)
|
||||||
|
return points
|
||||||
|
|
||||||
def team_points_in_cat(self, cat, team):
|
def team_points_in_cat(self, cat, team):
|
||||||
return self.points_by_cat_team.get((cat, team), 0)
|
return self.points_by_cat_team.get((cat, team), 0)
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
## Colors
|
|
||||||
##
|
|
||||||
def colors(teams):
|
|
||||||
colors = ['F0888A', '88BDF0', '00782B', '999900', 'EF9C00',
|
|
||||||
'F4B5B7', 'E2EFFB', '89CA9D', 'FAF519', 'FFE7BB',
|
|
||||||
'BA88F0', '8DCFF4', 'BEDFC4', 'FFFAB2', 'D7D7D7',
|
|
||||||
'C5B9D7', '006189', '8DCB41', 'FFCC00', '898989']
|
|
||||||
return dict(zip(teams, colors))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Testing
|
## Testing
|
||||||
|
@ -198,9 +190,8 @@ def test():
|
||||||
s.add((now, 'cat1', 'zebras', 20))
|
s.add((now, 'cat1', 'zebras', 20))
|
||||||
s.add((now, 'cat1', 'aardvarks', 10))
|
s.add((now, 'cat1', 'aardvarks', 10))
|
||||||
s.add((now, 'merf', 'aardvarks', 50))
|
s.add((now, 'merf', 'aardvarks', 50))
|
||||||
assert s.teams() == ['aardvarks', 'zebras']
|
assert s.get_teams() == ['aardvarks', 'zebras']
|
||||||
assert s.categories() == ['cat1', 'merf']
|
assert s.categories() == ['cat1', 'merf']
|
||||||
assert s.team_points('aardvarks') == 60
|
|
||||||
assert s.cat_points('cat1') == 30
|
assert s.cat_points('cat1') == 30
|
||||||
assert s.team_points_in_cat('cat1', 'aardvarks') == 10
|
assert s.team_points_in_cat('cat1', 'aardvarks') == 10
|
||||||
assert s.team_points_in_cat('merf', 'zebras') == 0
|
assert s.team_points_in_cat('merf', 'zebras') == 0
|
||||||
|
|
2
run.ctfd
2
run.ctfd
|
@ -1,4 +1,4 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
|
||||||
/usr/lib/ctf/ctfd.py 2>&1 | logger -t ctfd
|
exec /usr/lib/ctf/ctfd.py
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,64 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
|
import os
|
||||||
import config
|
import config
|
||||||
|
import teams
|
||||||
import points
|
import points
|
||||||
|
|
||||||
|
flags_dir = config.get('global', 'flags_dir')
|
||||||
|
house_team = config.get('global', 'house_team')
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
s = points.Storage()
|
s = points.Storage()
|
||||||
|
|
||||||
teams = s.teams()
|
|
||||||
categories = [(cat, s.cat_points(cat)) for cat in s.categories()]
|
categories = [(cat, s.cat_points(cat)) for cat in s.categories()]
|
||||||
teamcolors = points.colors(teams)
|
|
||||||
|
|
||||||
print('Content-type: text/html')
|
print('Content-type: text/html')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
print('''<?xml version="1.0" encoding="UTF-8" ?>
|
print('''<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>CTF Scoreboard</title>
|
<title>Scoreboard</title>
|
||||||
<link rel="stylesheet" href="%sctf.css" type="text/css" />
|
<link rel="stylesheet" href="%sctf.css" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Scoreboard</h1>
|
<h1>Scoreboard</h1>
|
||||||
''' % config.base_url)
|
''' % config.base_url)
|
||||||
print('<table>')
|
print('<table class="scoreboard">')
|
||||||
print('<tr>')
|
print('<tr>')
|
||||||
|
print('<th>Overall</th>')
|
||||||
for cat, score in categories:
|
for cat, score in categories:
|
||||||
print('<th>%s (%d)</th>' % (cat, score))
|
print('<th>')
|
||||||
|
print(' %s (%d)' % (cat, score))
|
||||||
|
try:
|
||||||
|
fn = os.path.join(flags_dir, cat)
|
||||||
|
team = open(fn).read() or house_team
|
||||||
|
print(' <br/>')
|
||||||
|
print(' <!-- flag: %s --> flag: <span style="color: #%s">%s</span>'
|
||||||
|
% (cat, teams.color(team), team))
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
print('</th>')
|
||||||
print('</tr>')
|
print('</tr>')
|
||||||
|
|
||||||
print('<tr>')
|
print('<tr>')
|
||||||
|
print('<td><ol>')
|
||||||
|
totals = []
|
||||||
|
for team in s.teams:
|
||||||
|
total = s.team_points(team)
|
||||||
|
totals.append((total, team))
|
||||||
|
for total, team in sorted(totals, reverse=True):
|
||||||
|
print('<li><span style="color: #%s;">%s (%0.3f)</span></li>'
|
||||||
|
% (teams.color(team), team, total))
|
||||||
|
print('</ol></td>')
|
||||||
for cat, total in categories:
|
for cat, total in categories:
|
||||||
print('<td style="height: 400px;">')
|
print('<td>')
|
||||||
scores = sorted([(s.team_points_in_cat(cat, team), team) for team in teams])
|
scores = sorted([(s.team_points_in_cat(cat, team), team) for team in s.teams])
|
||||||
for score, team in scores:
|
for score, team in scores:
|
||||||
color = teamcolors[team]
|
color = teams.color(team)
|
||||||
print('<div style="height: %f%%; overflow: hidden; background: #%s; color: black;">' % (float(score * 100)/total, color))
|
print('<div style="height: %f%%; overflow: hidden; background: #%s; color: black;">' % (float(score * 100)/total, color))
|
||||||
print('<!-- category: %s --> %s: %d' % (cat, team, score))
|
print('<!-- category: %s --> %s: %d' % (cat, team, score))
|
||||||
print('</div>')
|
print('</div>')
|
||||||
|
|
25
teams.py
25
teams.py
|
@ -2,12 +2,13 @@
|
||||||
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import time
|
import time
|
||||||
|
import config
|
||||||
import os
|
import os
|
||||||
from urllib.parse import quote, unquote
|
from urllib.parse import quote, unquote
|
||||||
|
|
||||||
house = 'dirtbags'
|
house = config.get('global', 'house_team')
|
||||||
|
passwdfn = config.get('global', 'passwd')
|
||||||
passwdfn = '/var/lib/ctf/passwd'
|
team_colors = config.get('global', 'team_colors')
|
||||||
|
|
||||||
teams = {}
|
teams = {}
|
||||||
built = 0
|
built = 0
|
||||||
|
@ -25,7 +26,9 @@ def build_teams():
|
||||||
for line in f:
|
for line in f:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
team, passwd = [unquote(v) for v in line.strip().split('\t')]
|
team, passwd = [unquote(v) for v in line.strip().split('\t')]
|
||||||
teams[team] = passwd
|
color = team_colors.pop(0)
|
||||||
|
team_colors.append(color)
|
||||||
|
teams[team] = (passwd, color)
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
built = time.time()
|
built = time.time()
|
||||||
|
@ -35,7 +38,7 @@ def validate(team):
|
||||||
|
|
||||||
def chkpasswd(team, passwd):
|
def chkpasswd(team, passwd):
|
||||||
validate(team)
|
validate(team)
|
||||||
if teams.get(team) == passwd:
|
if teams.get(team, [None, None])[0] == passwd:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -51,3 +54,15 @@ def add(team, passwd):
|
||||||
fcntl.lockf(f, fcntl.LOCK_EX)
|
fcntl.lockf(f, fcntl.LOCK_EX)
|
||||||
f.seek(0, 2)
|
f.seek(0, 2)
|
||||||
f.write('%s\t%s\n' % (quote(team), quote(passwd)))
|
f.write('%s\t%s\n' % (quote(team), quote(passwd)))
|
||||||
|
|
||||||
|
def color(team):
|
||||||
|
t = teams.get(team)
|
||||||
|
if not t:
|
||||||
|
validate(team)
|
||||||
|
t = teams.get(team)
|
||||||
|
if not t:
|
||||||
|
return '888888'
|
||||||
|
return t[1]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue