mirror of https://github.com/dirtbags/moth.git
Somewhat working game
This commit adds: * Registration * Puzzler cgi script * Several puzzles * Style sheet for HTML
This commit is contained in:
parent
d638a3be0c
commit
5f39aff5de
|
@ -0,0 +1,21 @@
|
||||||
|
body {
|
||||||
|
background: #000;
|
||||||
|
color: #0f0;
|
||||||
|
}
|
||||||
|
.readme {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
a:link {
|
||||||
|
color: #ff0;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: #880;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #000;
|
||||||
|
background: #ff0;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: #000;
|
||||||
|
background: #f00;
|
||||||
|
}
|
3
flagd.py
3
flagd.py
|
@ -9,6 +9,7 @@ import hmac
|
||||||
import optparse
|
import optparse
|
||||||
import points
|
import points
|
||||||
import pointscli
|
import pointscli
|
||||||
|
import teams
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
key = b'My First Shared Secret (tm)'
|
key = b'My First Shared Secret (tm)'
|
||||||
|
@ -67,7 +68,7 @@ class Submitter(asyncore.dispatcher):
|
||||||
def set_flag(self, cat, team):
|
def set_flag(self, cat, team):
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
|
|
||||||
team = team or points.house
|
team = team or teams.house
|
||||||
|
|
||||||
if self.flags.get(cat) != team:
|
if self.flags.get(cat) != team:
|
||||||
self.flags[cat] = team
|
self.flags[cat] = team
|
||||||
|
|
33
game.py
33
game.py
|
@ -6,6 +6,7 @@ import asynchat
|
||||||
import socket
|
import socket
|
||||||
import traceback
|
import traceback
|
||||||
import time
|
import time
|
||||||
|
import teams
|
||||||
from errno import EPIPE
|
from errno import EPIPE
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +26,6 @@ class Listener(asyncore.dispatcher):
|
||||||
self.listen(4)
|
self.listen(4)
|
||||||
self.player_factory = player_factory
|
self.player_factory = player_factory
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.last_beat = 0
|
|
||||||
|
|
||||||
def handle_accept(self):
|
def handle_accept(self):
|
||||||
conn, addr = self.accept()
|
conn, addr = self.accept()
|
||||||
|
@ -34,9 +34,7 @@ class Listener(asyncore.dispatcher):
|
||||||
# has a reference to it for as long as it's open.
|
# has a reference to it for as long as it's open.
|
||||||
|
|
||||||
def readable(self):
|
def readable(self):
|
||||||
now = time.time()
|
self.manager.heartbeat(time.time())
|
||||||
if now > self.last_beat + pulse:
|
|
||||||
self.manager.heartbeat(now)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,11 +87,25 @@ class Manager:
|
||||||
self.lobby = set()
|
self.lobby = set()
|
||||||
self.contestants = []
|
self.contestants = []
|
||||||
self.last_beat = 0
|
self.last_beat = 0
|
||||||
|
self.timers = set()
|
||||||
|
|
||||||
def heartbeat(self, now):
|
def heartbeat(self, now):
|
||||||
# Called by listener to beat heart
|
"""Called by listener to beat heart."""
|
||||||
for game in list(self.games):
|
|
||||||
game.heartbeat(now)
|
now = time.time()
|
||||||
|
if now > self.last_beat + pulse:
|
||||||
|
for game in list(self.games):
|
||||||
|
game.heartbeat(now)
|
||||||
|
for event in self.timers:
|
||||||
|
when, cb = event
|
||||||
|
if now >= when:
|
||||||
|
self.timers.remove(event)
|
||||||
|
cb()
|
||||||
|
|
||||||
|
def add_timer(self, when, cb):
|
||||||
|
"""Add a timed callback."""
|
||||||
|
|
||||||
|
self.timers.add((when, cb))
|
||||||
|
|
||||||
def enter_lobby(self, player):
|
def enter_lobby(self, player):
|
||||||
self.lobby.add(player)
|
self.lobby.add(player)
|
||||||
|
@ -248,13 +260,14 @@ class Player(asynchat.async_chat):
|
||||||
cmd, args = val[0].lower(), val[1:]
|
cmd, args = val[0].lower(), val[1:]
|
||||||
|
|
||||||
if cmd == 'login':
|
if cmd == 'login':
|
||||||
if not self.name:
|
if self.name:
|
||||||
# XXX Check password
|
self.err('Already logged in.')
|
||||||
|
elif teams.chkpasswd(args[0], args[1]):
|
||||||
self.name = args[0]
|
self.name = args[0]
|
||||||
self.write('Welcome to the fray, %s.' % self.name)
|
self.write('Welcome to the fray, %s.' % self.name)
|
||||||
self.manager.enter_lobby(self)
|
self.manager.enter_lobby(self)
|
||||||
else:
|
else:
|
||||||
self.err('Already logged in.')
|
self.err('Invalid password.')
|
||||||
elif cmd == '^':
|
elif cmd == '^':
|
||||||
# Send to manager
|
# Send to manager
|
||||||
ret = self.manager.player_cmd(args)
|
ret = self.manager.player_cmd(args)
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import random
|
||||||
|
|
||||||
|
primes = [2, 3, 5, 7, 11, 13, 17, 19]
|
||||||
|
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
|
||||||
|
data = sys.stdin.read().strip()
|
||||||
|
jumble = ''.join(data.split())
|
||||||
|
|
||||||
|
lj = len(jumble)
|
||||||
|
below = (0, 0)
|
||||||
|
above = (lj, 2)
|
||||||
|
for i in primes:
|
||||||
|
for j in primes:
|
||||||
|
m = i * j
|
||||||
|
if (m < lj) and (m > below[0] * below[1]):
|
||||||
|
below = (i, j)
|
||||||
|
elif (m >= lj) and (m < (above[0] * above[1])):
|
||||||
|
above = (i, j)
|
||||||
|
|
||||||
|
for i in range(lj, (above[0] * above[1])):
|
||||||
|
jumble += random.choice(letters)
|
||||||
|
|
||||||
|
out = []
|
||||||
|
for i in range(above[0]):
|
||||||
|
for j in range(above[1]):
|
||||||
|
out.append(jumble[j*above[0] + i])
|
||||||
|
print(''.join(out))
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?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>Capture The Flag</title>
|
||||||
|
<link rel="stylesheet" href="ctf.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Capture The Flag</h1>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><a href="register.cgi">Register</a> your team</li>
|
||||||
|
<li><a href="scoreboard.cgi">Scoreboard</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Some challenges are <a href="puzzler.cgi">puzzles</a>. Some are
|
||||||
|
sitting on the network; you must find these yourself!
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -4,9 +4,7 @@ import socket
|
||||||
import hmac
|
import hmac
|
||||||
import struct
|
import struct
|
||||||
import io
|
import io
|
||||||
|
import teams
|
||||||
## Name of the house team
|
|
||||||
house = 'dirtbags'
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
24
pointscli.py
24
pointscli.py
|
@ -6,10 +6,17 @@ import points
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
|
||||||
def submit(sock, cat, team, score):
|
def makesock(host):
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s.connect((host, 6667))
|
||||||
|
return s
|
||||||
|
|
||||||
|
def submit(cat, team, score, sock=None):
|
||||||
|
if not sock:
|
||||||
|
sock = makesock('cfl-sunray1')
|
||||||
begin = time.time()
|
begin = time.time()
|
||||||
mark = int(begin)
|
mark = int(begin)
|
||||||
req = points.encode_request(mark, cat, team, score)
|
req = points.encode_request(1, mark, cat, team, score)
|
||||||
while True:
|
while True:
|
||||||
sock.send(req)
|
sock.send(req)
|
||||||
r, w, x = select.select([sock], [], [], begin + 2 - time.time())
|
r, w, x = select.select([sock], [], [], begin + 2 - time.time())
|
||||||
|
@ -17,12 +24,12 @@ def submit(sock, cat, team, score):
|
||||||
break
|
break
|
||||||
b = sock.recv(500)
|
b = sock.recv(500)
|
||||||
try:
|
try:
|
||||||
when, cat_, txt = points.decode_response(b)
|
id, txt = points.decode_response(b)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Ignore invalid packets
|
# Ignore invalid packets
|
||||||
continue
|
continue
|
||||||
if (when != mark) or (cat_ != cat):
|
if id != 1:
|
||||||
# Ignore wrong timestamp
|
# Ignore wrong ID
|
||||||
continue
|
continue
|
||||||
if txt == 'OK':
|
if txt == 'OK':
|
||||||
return
|
return
|
||||||
|
@ -30,11 +37,6 @@ def submit(sock, cat, team, score):
|
||||||
raise ValueError(txt)
|
raise ValueError(txt)
|
||||||
|
|
||||||
|
|
||||||
def makesock(host):
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
s.connect((host, 6667))
|
|
||||||
return s
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
p = optparse.OptionParser(usage='%prog CATEGORY TEAM SCORE')
|
p = optparse.OptionParser(usage='%prog CATEGORY TEAM SCORE')
|
||||||
p.add_option('-s', '--host', dest='host', default='localhost',
|
p.add_option('-s', '--host', dest='host', default='localhost',
|
||||||
|
@ -50,7 +52,7 @@ def main():
|
||||||
s = makesock(opts.host)
|
s = makesock(opts.host)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
submit(s, cat, team, score)
|
submit(cat, team, score, sock=s)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
print(err)
|
print(err)
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -34,11 +34,11 @@ class MyHandler(asyncore.dispatcher):
|
||||||
team = team or house
|
team = team or house
|
||||||
|
|
||||||
# Replays can happen legitimately.
|
# Replays can happen legitimately.
|
||||||
if not (id in self.acked):
|
if not ((peer, id) in self.acked):
|
||||||
if not (now - 2 < when <= now):
|
if not (now - 2 < when <= now):
|
||||||
return self.respond(peer, id, 'Your clock is off')
|
return self.respond(peer, id, 'Your clock is off')
|
||||||
self.store.add((when, cat, team, score))
|
self.store.add((when, cat, team, score))
|
||||||
self.acked.add(id)
|
self.acked.add((peer, id))
|
||||||
|
|
||||||
self.respond(peer, id, 'OK')
|
self.respond(peer, id, 'OK')
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import cgitb; cgitb.enable()
|
||||||
|
import cgi
|
||||||
|
import os
|
||||||
|
import fcntl
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import pointscli
|
||||||
|
import teams
|
||||||
|
|
||||||
|
cat_re = re.compile(r'^[a-z]+$')
|
||||||
|
points_re = re.compile(r'^[0-9]+$')
|
||||||
|
|
||||||
|
def dbg(*vals):
|
||||||
|
print('Content-type: text/plain\n\n')
|
||||||
|
print(*vals)
|
||||||
|
|
||||||
|
|
||||||
|
points_by_cat = {}
|
||||||
|
points_by_team = {}
|
||||||
|
try:
|
||||||
|
for line in open('puzzler.dat'):
|
||||||
|
line = line.strip()
|
||||||
|
cat, team, pts = line.split('\t')
|
||||||
|
pts = int(pts)
|
||||||
|
points_by_cat[cat] = max(points_by_cat.get(cat, 0), pts)
|
||||||
|
points_by_team.setdefault((team, cat), set()).add(pts)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
f = cgi.FieldStorage()
|
||||||
|
|
||||||
|
cat = f.getfirst('c')
|
||||||
|
points = f.getfirst('p')
|
||||||
|
team = f.getfirst('t')
|
||||||
|
passwd = f.getfirst('w')
|
||||||
|
key = f.getfirst('k')
|
||||||
|
|
||||||
|
verboten = ['key', 'index.html']
|
||||||
|
|
||||||
|
def start_html(title):
|
||||||
|
print('''Content-type: text/html
|
||||||
|
|
||||||
|
<?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="ctf.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>%s</h1>
|
||||||
|
''' % (title, title))
|
||||||
|
|
||||||
|
def end_html():
|
||||||
|
print('</body></html>')
|
||||||
|
|
||||||
|
|
||||||
|
def safe_join(*args):
|
||||||
|
safe = []
|
||||||
|
for a in args:
|
||||||
|
if not a:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
a = a.replace('..', '')
|
||||||
|
a = a.replace('/', '')
|
||||||
|
safe.append(a)
|
||||||
|
ret = '/'.join(safe)
|
||||||
|
if os.path.exists(ret):
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def dump_file(fn):
|
||||||
|
f = open(fn, 'rb')
|
||||||
|
while True:
|
||||||
|
d = f.read(4096)
|
||||||
|
if not d:
|
||||||
|
break
|
||||||
|
sys.stdout.buffer.write(d)
|
||||||
|
|
||||||
|
def show_cats():
|
||||||
|
start_html('Categories')
|
||||||
|
print('<ul>')
|
||||||
|
for p in sorted(os.listdir('puzzles')):
|
||||||
|
print('<li><a href="puzzler.cgi?c=%s">%s</a></li>' % (p, p))
|
||||||
|
print('</ul>')
|
||||||
|
end_html()
|
||||||
|
|
||||||
|
|
||||||
|
def show_puzzles(cat, cat_dir):
|
||||||
|
start_html('Open in %s' % cat)
|
||||||
|
opened = points_by_cat.get(cat, 0)
|
||||||
|
puzzles = sorted([int(v) for v in os.listdir(cat_dir)])
|
||||||
|
if puzzles:
|
||||||
|
print('<ul>')
|
||||||
|
opened = max(opened, puzzles[0])
|
||||||
|
for p in puzzles:
|
||||||
|
if p <= opened:
|
||||||
|
print('<li><a href="puzzler.cgi?c=%s&p=%d">%d</a></li>' % (cat, p, p))
|
||||||
|
print('</ul>')
|
||||||
|
else:
|
||||||
|
print('<p>None (someone is slacking)</p>')
|
||||||
|
end_html()
|
||||||
|
|
||||||
|
def show_puzzle(cat, points, points_dir):
|
||||||
|
# Show puzzle in cat for points
|
||||||
|
start_html('%s for %s' % (cat, points))
|
||||||
|
fn = os.path.join(points_dir, 'index.html')
|
||||||
|
if os.path.exists(fn):
|
||||||
|
print('<div class="readme">')
|
||||||
|
dump_file(fn)
|
||||||
|
print('</div>')
|
||||||
|
print('<ul>')
|
||||||
|
for fn in sorted(os.listdir(points_dir)):
|
||||||
|
if fn.endswith('~') or fn.startswith('.') or fn in verboten:
|
||||||
|
continue
|
||||||
|
print('<li><a href="puzzler.cgi?c=%s&p=%s&f=%s">%s</a></li>' % (cat, points, fn, fn))
|
||||||
|
print('</ul>')
|
||||||
|
print('<form action="puzzler.cgi" method="post">')
|
||||||
|
print('<input type="hidden" name="c" value="%s" />' % cat)
|
||||||
|
print('<input type="hidden" name="p" value="%s" />' % points)
|
||||||
|
print('Team: <input name="t" /><br />')
|
||||||
|
print('Password: <input type="password" name="w" /><br />')
|
||||||
|
print('Key: <input name="k" /><br />')
|
||||||
|
print('<input type="submit" />')
|
||||||
|
print('</form>')
|
||||||
|
end_html()
|
||||||
|
|
||||||
|
def win(cat, team, points):
|
||||||
|
start_html('Winner!')
|
||||||
|
points = int(points)
|
||||||
|
pointscli.submit(cat, team, points)
|
||||||
|
end_html()
|
||||||
|
f = open('puzzler.dat', 'a')
|
||||||
|
fctnl.lockf(f, LOCK_EX)
|
||||||
|
f.write('%s\t%s\t%d\n' % (cat, team, points))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
cat_dir = safe_join('puzzles', cat)
|
||||||
|
points_dir = safe_join('puzzles', cat, points)
|
||||||
|
|
||||||
|
if not cat_dir:
|
||||||
|
# Show categories
|
||||||
|
show_cats()
|
||||||
|
elif not points_dir:
|
||||||
|
# Show available puzzles in category
|
||||||
|
show_puzzles(cat, cat_dir)
|
||||||
|
elif not (team and passwd and key):
|
||||||
|
fn = f.getfirst('f')
|
||||||
|
if fn in verboten:
|
||||||
|
fn = None
|
||||||
|
fn = safe_join('puzzles', cat, points, fn)
|
||||||
|
if fn:
|
||||||
|
# Provide a file from this directory
|
||||||
|
print('Content-type: application/octet-stream')
|
||||||
|
print()
|
||||||
|
dump_file(fn)
|
||||||
|
else:
|
||||||
|
show_puzzle(cat, points, points_dir)
|
||||||
|
else:
|
||||||
|
thekey = open('%s/key' % points_dir).read().strip()
|
||||||
|
if not teams.chkpasswd(team, passwd):
|
||||||
|
start_html('Wrong password')
|
||||||
|
end_html()
|
||||||
|
elif key != thekey:
|
||||||
|
show_puzzle(cat, points, points_dir)
|
||||||
|
elif points_by_team.get((team, cat)):
|
||||||
|
start_html('Greedy greedy')
|
||||||
|
end_html()
|
||||||
|
else:
|
||||||
|
win(cat, team, points)
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1 @@
|
||||||
|
antediluvian
|
Binary file not shown.
After Width: | Height: | Size: 87 B |
|
@ -0,0 +1 @@
|
||||||
|
tkftsuiuqvaheohrnsnuoleyriod"eic"
|
|
@ -0,0 +1 @@
|
||||||
|
unequivocal
|
|
@ -0,0 +1 @@
|
||||||
|
27586126814341379597440261571645814840581961154587430529221052323
|
|
@ -0,0 +1 @@
|
||||||
|
DB1663<3
|
|
@ -0,0 +1,13 @@
|
||||||
|
<p>Kolejne modele Panzerfausta, odpowiednio: 60, 100, 150, różnił kaliber głowicy i wielkość ładunku miotającego. Konstrukcja i mechanizm nie ulegał istotnym zmianom, z racji wzrastania zasięgu broni modyfikacjom ulegały nastawy celowników. Jedynie we wzorze 150 wprowadzono (a był to już początek 1945 roku) wielokrotne użycie wyrzutni rurowej. Osiągnięto to przez umieszczenie ładunku miotającego w głowicy oraz przez wzmocnienie rury. W wyniku problemu z transportem model ów nie wszedł do walki. Model 250 (o teoretycznym zasięgu 250 m) z racji zakończenia wojny nie opuścił desek kreślarskich nigdy nie wchodząc nawet w fazę prototypową.</p>
|
||||||
|
<pre>(61, 4)
|
||||||
|
(47, 8)
|
||||||
|
(19, 4)
|
||||||
|
(37, 1)
|
||||||
|
(51, 3)
|
||||||
|
(67, 5)
|
||||||
|
(9, 2)
|
||||||
|
(26, 1)
|
||||||
|
(2, 2)
|
||||||
|
(26, 3)
|
||||||
|
(50, 2)</pre>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
jako561962
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
31 9 15 26 14 23 14 6 18 5 12 18 5 2 16 27 7 10 11 5 13 31 17 17 6 2 26 26 10 21 10 8 20 4
|
|
@ -0,0 +1 @@
|
||||||
|
journals.uchicago
|
|
@ -0,0 +1 @@
|
||||||
|
xez.3nt
|
|
@ -0,0 +1,62 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import cgitb; cgitb.enable()
|
||||||
|
import cgi
|
||||||
|
import teams
|
||||||
|
import fcntl
|
||||||
|
import string
|
||||||
|
|
||||||
|
print('Content-type: text/html')
|
||||||
|
print()
|
||||||
|
|
||||||
|
f = cgi.FieldStorage()
|
||||||
|
|
||||||
|
team = f.getfirst('team', '')
|
||||||
|
pw = f.getfirst('pw')
|
||||||
|
confirm_pw = f.getfirst('confirm_pw')
|
||||||
|
|
||||||
|
html = string.Template('''<?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="ctf.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Team Registration</h1>
|
||||||
|
|
||||||
|
<form method="post" action="register.cgi">
|
||||||
|
<fieldset>
|
||||||
|
<label>Desired Team Team:</label>
|
||||||
|
<input type="text" name="team" />
|
||||||
|
<span class="error">$team_error</span><br />
|
||||||
|
|
||||||
|
<label>Password:</label>
|
||||||
|
<input type="password" name="pw" /> <br />
|
||||||
|
|
||||||
|
<label>Confirm Password:</label>
|
||||||
|
<input type="password" name="confirm_pw" />
|
||||||
|
<span class="error">$pw_match_error</span><br />
|
||||||
|
|
||||||
|
<input type="submit" value="Register" />
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
''')
|
||||||
|
|
||||||
|
if not (team and pw and confirm_pw): #If we're starting from the beginning?
|
||||||
|
html = html.substitute(team_error='',
|
||||||
|
pw_match_error='')
|
||||||
|
elif teams.exists(team):
|
||||||
|
html = html.substitute(team_error='Team team already taken',
|
||||||
|
pw_match_error='')
|
||||||
|
elif pw != confirm_pw:
|
||||||
|
html = html.substitute(team_error='',
|
||||||
|
pw_match_error='Passwords do not match')
|
||||||
|
else:
|
||||||
|
teams.add(team, pw)
|
||||||
|
html = 'Team registered.'
|
||||||
|
|
||||||
|
print(html)
|
|
@ -17,9 +17,10 @@ print('''<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
"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>yo mom</title>
|
<title>CTF Scoreboard</title>
|
||||||
|
<link rel="stylesheet" href="ctf.css" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body style="background: black; color: white;">
|
<body>
|
||||||
<h1>Scoreboard</h1>
|
<h1>Scoreboard</h1>
|
||||||
''')
|
''')
|
||||||
print('<table>')
|
print('<table>')
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
|
import fcntl
|
||||||
|
|
||||||
|
house = 'dirtbags'
|
||||||
|
|
||||||
|
teams = None
|
||||||
|
|
||||||
|
def build_teams():
|
||||||
|
global teams
|
||||||
|
|
||||||
|
teams = {}
|
||||||
|
try:
|
||||||
|
f = open('passwd')
|
||||||
|
for line in f:
|
||||||
|
team, passwd = line.strip().split('\t')
|
||||||
|
teams[team] = passwd
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def chkpasswd(team, passwd):
|
||||||
|
if teams is None:
|
||||||
|
build_teams()
|
||||||
|
if teams.get(team) == passwd:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def exists(team):
|
||||||
|
if teams is None:
|
||||||
|
build_teams()
|
||||||
|
if team == house:
|
||||||
|
return True
|
||||||
|
return team in teams
|
||||||
|
|
||||||
|
def add(team, passwd):
|
||||||
|
f = open('passwd', 'a')
|
||||||
|
fcntl.lockf(f, fcntl.LOCK_EX)
|
||||||
|
f.seek(0, 2)
|
||||||
|
f.write('%s\t%s\n' % (team, passwd))
|
Loading…
Reference in New Issue