146 lines
6.0 KiB
Python
Executable File
146 lines
6.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import os
|
|
import docker
|
|
import ipaddress
|
|
from twisted.protocols.basic import LineReceiver
|
|
from twisted.internet.protocol import Factory, Protocol
|
|
from twisted.internet.endpoints import TCP4ServerEndpoint
|
|
from twisted.internet import reactor
|
|
|
|
class SLBRManager(Protocol):
|
|
def __init__(self, config):
|
|
self.client_addr = None
|
|
self.config = config
|
|
def suicide(self):
|
|
slbr_containers = self.config['docker_client'].containers.list(
|
|
filters = {'label': 'description=SLBR User Container'}
|
|
)
|
|
for container in slbr_containers:
|
|
if container.attrs['NetworkSettings']['Networks']['slbr']['IPAddress'] == self.client_addr:
|
|
container.remove(force=True)
|
|
|
|
def connectionMade(self):
|
|
self.client_addr = self.transport.getPeer().host
|
|
if (
|
|
ipaddress.ip_address(self.client_addr)
|
|
not in
|
|
ipaddress.ip_network(self.config['docker_netmask'])
|
|
):
|
|
print('Dropping client {} not in docker network'.format(self.client_addr))
|
|
self.transport.loseConnection()
|
|
|
|
def dataReceived(self, data):
|
|
message = data.decode('utf8').split(' ')
|
|
command = message[0].replace('\n', '')
|
|
if len(message) > 1:
|
|
args = message[1:]
|
|
|
|
if command == 'LOG':
|
|
entry = '[{}]: {}'.format(self.client_addr, ' '.join(args))
|
|
print(entry)
|
|
|
|
elif command == 'DEAD':
|
|
print('Killing {}'.format(self.client_addr))
|
|
self.suicide()
|
|
self.transport.loseConnection()
|
|
elif command == 'SCORE':
|
|
message = 'PLAYER | CHALLENGES COMPLETED\n' + ('-' * 30) + '\n'
|
|
slbr_containers = self.config['docker_client'].containers.list(
|
|
filters = {'label': 'description=SLBR User Container'}
|
|
)
|
|
for player_addr in os.listdir('./scores'):
|
|
player_name = 'err'
|
|
for container in slbr_containers:
|
|
if container.attrs['NetworkSettings']['Networks']['slbr']['IPAddress'] == player_addr:
|
|
player_name = container.attrs['Config']['Image'].replace('slbr:', '')
|
|
break
|
|
message += player_name + ': '
|
|
with open('./scores/{}'.format(player_addr)) as score_file:
|
|
completed_challenges = ', '.join(score_file.readlines()).replace('\n', '')
|
|
message += completed_challenges + '\n'
|
|
|
|
self.transport.write(bytes(message, 'utf8'))
|
|
self.transport.loseConnection()
|
|
elif command == 'SUBMIT' and len(args) == 2:
|
|
try:
|
|
challenge_num = int(args[0])
|
|
except ValueError:
|
|
self.transport.loseConnection()
|
|
return
|
|
|
|
submitted_solution = args[1].replace('\n', '')
|
|
with open(self.config['solutions_file']) as solutions_file:
|
|
correct_solutions = solutions_file.readlines()
|
|
correct_solutions = list(map(lambda x: x.replace('\n', ''), correct_solutions))
|
|
num_solutions = len(correct_solutions)
|
|
|
|
print(
|
|
'{} submitted \"{}\" as solution for challenge {}'.format(
|
|
self.client_addr,
|
|
submitted_solution,
|
|
challenge_num
|
|
)
|
|
)
|
|
|
|
game_ended = False
|
|
if challenge_num <= num_solutions:
|
|
print('(Correct answer is {})'.format(correct_solutions[challenge_num -1]))
|
|
|
|
if correct_solutions[challenge_num -1] == submitted_solution:
|
|
message = 'w00t! You got the right answer!!!'
|
|
|
|
with open(
|
|
'{}/{}'.format(
|
|
self.config['scores_folder'],
|
|
self.client_addr
|
|
), 'a+'
|
|
) as score_file:
|
|
score_file.seek(0)
|
|
completed_challenges = score_file.readlines()
|
|
completed_challenges = list(
|
|
map(lambda x: x.replace('\n', ''), completed_challenges)
|
|
)
|
|
if str(challenge_num) in completed_challenges:
|
|
message = 'You already submitted the correct answer for that challenge!'
|
|
else:
|
|
score_file.write(str(challenge_num) + '\n')
|
|
if len(completed_challenges) + 1 == num_solutions:
|
|
message = (
|
|
'w00t! You got the right answer!!!\n'
|
|
+ 'Hey! thats all {}! that means YOU WIN!\n'.format(num_solutions)
|
|
+ '!!!!!!!CONGRATULATIONS!!!!!!!\n'
|
|
+ 'THIS CONTAINER WILL NOW SELF DESTRUCT'
|
|
)
|
|
game_ended = True
|
|
else:
|
|
message = '|X_x| answer was rejected!!!.'
|
|
else:
|
|
message = ('What? You tried to submit a solution for challenge '
|
|
+ '{} but there are only {} challenges!'.format(
|
|
challenge_num,
|
|
num_solutions
|
|
))
|
|
|
|
print(message.replace('You', 'User'))
|
|
self.transport.write(bytes(message + '\n', 'utf8'))
|
|
self.transport.loseConnection()
|
|
if game_ended:
|
|
self.suicide()
|
|
|
|
class SLBRManagerFactory(Factory):
|
|
def __init__(self, config):
|
|
self.config = config
|
|
def buildProtocol(self, addr):
|
|
return SLBRManager(self.config)
|
|
|
|
docker_client = docker.from_env()
|
|
endpoint = TCP4ServerEndpoint(reactor, 1337)
|
|
endpoint.listen(SLBRManagerFactory({
|
|
'docker_client': docker_client,
|
|
'docker_netmask': '172.19.0.0/16',
|
|
'scores_folder': './scores',
|
|
'solutions_file': './solutions.txt',
|
|
'log_file': './log.txt'
|
|
}))
|
|
reactor.run()
|