def post(self): data = flask.request.get_json() unlocked = data.get('unlocked', False) answer = utils.normalize_input(data['answer']) chall = models.Challenge.create( data['name'], data['description'], data['points'], '', data['cat_slug'], unlocked, data.get('validator', validators.GetDefaultValidator())) validator = validators.GetValidatorForChallenge(chall) validator.change_answer(answer) if 'attachments' in data: chall.set_attachments(data['attachments']) if 'prerequisite' in data: chall.set_prerequisite(data['prerequisite']) if 'tags' in data: chall.set_tags(data['tags']) if unlocked and utils.GameTime.open(): news = 'New challenge created: "%s"' % chall.name models.News.game_broadcast(message=news) models.commit() app.logger.info('Challenge %s created by %r.', chall, models.User.current()) return chall
def _delete_all(self): for u in models.User.query.filter( models.User.api_key != None).all(): # noqa: E711 u.api_key = None u.api_key_updated = datetime.datetime.now() models.commit() return dict(status='OK')
def post_admin(self, data): cid = data.get('cid', None) tid = data.get('tid', None) if not cid or not tid: raise errors.ValidationError('Requires team and challenge.') challenge = models.Challenge.query.get(data['cid']) team = models.Team.query.get(data['tid']) if not challenge or not team: raise errors.ValidationError('Requires team and challenge.') user = models.User.current() app.challenge_log.info( 'Admin %s <%s> submitting flag for challenge %s <%d>, ' 'team %s <%d>', user.nick, user.email, challenge.name, challenge.cid, team.name, team.tid) try: points = controllers.save_team_answer(challenge, team, None) models.commit() except (errors.IntegrityError, errors.FlushError) as ex: app.logger.exception( 'Unable to save answer for %s/%s: %s', str(data['tid']), str(data['tid']), str(ex)) models.db.session.rollback() raise errors.AccessDeniedError( 'Unable to save answer for team. See log for details.') cache.delete('cats/%d' % tid) cache.delete('scoreboard') return dict(points=points)
def post(self): data = flask.request.get_json() unlocked = data.get('unlocked', False) answer = utils.normalize_input(data['answer']) chall = models.Challenge.create( data['name'], data['description'], data['points'], answer, data['cat_slug'], unlocked) if 'attachments' in data: chall.set_attachments(data['attachments']) if 'prerequisite' in data: chall.set_prerequisite(data['prerequisite']) if 'tags' in data: chall.set_tags(data['tags']) if unlocked and utils.GameTime.open(): news = 'New challenge created: "%s"' % chall.name models.News.game_broadcast(message=news) models.commit() app.logger.info('Challenge %s created by %r.', chall, models.User.current()) return chall
def post(self): data = flask.request.get_json() unlocked = data.get('unlocked', False) answer = utils.normalize_input(data['answer']) if not validators.IsValidator(data.get('validator', None)): raise errors.ValidationError('Invalid validator.') chall = models.Challenge.create( data['name'], data['description'], data['points'], '', unlocked, data.get('validator', validators.GetDefaultValidator())) validator = validators.GetValidatorForChallenge(chall) validator.change_answer(answer) if 'attachments' in data: chall.set_attachments(data['attachments']) if 'prerequisite' in data: chall.set_prerequisite(data['prerequisite']) if 'tags' in data: chall.set_tags(data['tags']) if unlocked and utils.GameTime.open(): news = 'New challenge created: "%s"' % chall.name models.News.game_broadcast(message=news) models.commit() app.logger.info('Challenge %s created by %r.', chall, models.User.current()) return chall
def make_challenges(cats, tags): challs = [] chall_words = ( 'Magic', 'Grand', 'Fast', 'Hash', 'Table', 'Password', 'Crypto', 'Alpha', 'Beta', 'Win', 'Socket', 'Ball', 'Stego', 'Word', 'Gamma', 'Native', 'Mine', 'Dump', 'Tangled', 'Hackers', 'Book', 'Delta', 'Shadow', 'Lose', 'Draw', 'Long', 'Pointer', 'Free', 'Not', 'Only', 'Live', 'Secret', 'Agent', 'Hax0r', 'Whiskey', 'Tango', 'Foxtrot') for _ in xrange(25): title = random.sample(chall_words, 3) random.shuffle(title) title = ' '.join(title) flag = '_'.join(random.sample(chall_words, 4)).lower() cat = random.choice(cats) #Choose a random subset of tags numtags = random.randint(0, len(tags)-1) local_tags = random.sample(tags, numtags) points = random.randint(1, 20) * 100 desc = 'Flag: ' + flag ch = models.Challenge.create(title, desc, points, flag, cat.slug, unlocked=True) ch.add_tags(local_tags) if len(challs) % 8 == 7: ch.prerequisite = json.dumps( {'type': 'solved', 'challenge': challs[-1].cid}) # TODO: attachments challs.append(ch) models.commit() return challs
def put(self, challenge_id): challenge = models.Challenge.query.get_or_404(challenge_id) data = flask.request.get_json() old_unlocked = challenge.unlocked for field in ( 'name', 'description', 'points', 'cat_slug', 'unlocked', 'weight'): setattr( challenge, field, data.get(field, getattr(challenge, field))) if 'answer' in data and data['answer']: answer = utils.normalize_input(data['answer']) challenge.change_answer(answer) if 'attachments' in data: challenge.set_attachments(data['attachments']) if 'prerequisite' in data: challenge.set_prerequisite(data['prerequisite']) else: challenge.prerequisite = '' if 'tags' in data: challenge.set_tags(data['tags']) if challenge.unlocked and not old_unlocked: news = 'Challenge "%s" unlocked!' % challenge.name models.News.game_broadcast(message=news) app.logger.info('Challenge %s updated by %r.', challenge, models.User.current()) models.commit() cache.clear() return challenge
def change_user_team(uid, team_tid, code): """Provide an interface for changing a user's team""" team = models.Team.query.get_or_404(team_tid) user = models.User.query.get_or_404(uid) old_team = user.team if code.lower() != team.code.lower(): raise errors.ValidationError('Invalid team selection or team code') if team.tid == user.team_tid: raise errors.ValidationError('Changing to same team') app.logger.info('User %s switched to team %s from %s' % (user.nick, team.name, old_team.name)) user.team = team user.team_tid = team_tid flask.session['team'] = team_tid if old_team.players.count() == 0 and len(old_team.answers) == 0: app.logger.info('Removing team %s due to lack of players' % old_team.name) models.db.session.delete(old_team) models.commit()
def testGetByApiKey(self): token = 'a'*32 self.user.api_key = token models.commit() self.assertEqual( self.user.nick, models.User.get_by_api_key(token).nick) self.assertIsNone(models.User.get_by_api_key(token[:-1]))
def put(self, user_id): if not flask.g.uid == user_id and not flask.g.admin: raise errors.AccessDeniedError('No access to that user.') user = models.User.query.get_or_404(user_id) data = flask.request.get_json() if utils.is_admin() and 'admin' in data: if data['admin'] and not user.admin: try: user.promote() except AssertionError: raise errors.ValidationError( 'Error promoting. Has player solved challenges?') else: user.admin = False if data.get('password'): user.set_password(data['password']) if utils.is_admin(): user.nick = data['nick'] if not app.config.get('TEAMS') and user.team: user.team.name = data['nick'] try: models.commit() except AssertionError: raise errors.ValidationError( 'Error in updating user. Details are logged.') return user
def setUp(self): super(NewsTest, self).setUp() models.News.broadcast('test', 'Test message.') models.News.unicast( self.authenticated_client.team.tid, 'test', 'Test team message.') models.commit()
def put(self, challenge_id): challenge = models.Challenge.query.get_or_404(challenge_id) data = flask.request.get_json() old_unlocked = challenge.unlocked for field in ( 'name', 'description', 'points', 'cat_slug', 'unlocked', 'weight', 'validator'): setattr( challenge, field, data.get(field, getattr(challenge, field))) if 'answer' in data and data['answer']: answer = utils.normalize_input(data['answer']) validator = validators.GetValidatorForChallenge(challenge) validator.change_answer(answer) if 'attachments' in data: challenge.set_attachments(data['attachments']) if 'prerequisite' in data: challenge.set_prerequisite(data['prerequisite']) else: challenge.prerequisite = '' if 'tags' in data: challenge.set_tags(data['tags']) if challenge.unlocked and not old_unlocked: news = 'Challenge "%s" unlocked!' % challenge.name models.News.game_broadcast(message=news) app.logger.info('Challenge %s updated by %r.', challenge, models.User.current()) models.commit() cache.clear() return challenge
def put(self, user_id): if not flask.g.user.uid == user_id and not flask.g.user.admin: raise errors.AccessDeniedError('No access to that user.') user = models.User.query.get_or_404(user_id) data = flask.request.get_json() promoting = False if utils.is_admin() and 'admin' in data: if data['admin'] and not user.admin: user.promote() promoting = True else: user.admin = False if data.get('password'): user.set_password(data['password']) if utils.is_admin(): user.nick = data['nick'] if not app.config.get('TEAMS', False): user.team.name = data['nick'] try: models.commit() except AssertionError: if promoting: raise errors.ValidationError('Error promoting. ' 'Has player solved challenges?') raise return user
def post(self): data = flask.request.get_json() points = controllers.submit_answer(data['cid'], data['answer']) models.commit() cache.delete_team('cats/%d') cache.delete('scoreboard') return dict(points=points)
def make_challenges(tags): challs = [] chall_words = ('Magic', 'Grand', 'Fast', 'Hash', 'Table', 'Password', 'Crypto', 'Alpha', 'Beta', 'Win', 'Socket', 'Ball', 'Stego', 'Word', 'Gamma', 'Native', 'Mine', 'Dump', 'Tangled', 'Hackers', 'Book', 'Delta', 'Shadow', 'Lose', 'Draw', 'Long', 'Pointer', 'Free', 'Not', 'Only', 'Live', 'Secret', 'Agent', 'Hax0r', 'Whiskey', 'Tango', 'Foxtrot') for _ in range(25): title = random.sample(chall_words, 3) random.shuffle(title) title = ' '.join(title) flag = '_'.join(random.sample(chall_words, 4)).lower() # Choose a random subset of tags numtags = random.randint(0, len(tags) - 1) local_tags = random.sample(tags, numtags) points = random.randint(1, 20) * 100 desc = 'Flag: ' + flag ch = models.Challenge.create(title, desc, points, flag, unlocked=True) ch.add_tags(local_tags) if len(challs) % 8 == 7: ch.prerequisite = json.dumps({ 'type': 'solved', 'challenge': challs[-1].cid }) # TODO: attachments challs.append(ch) models.commit() return challs
def post_admin(self, data): cid = data.get('cid', None) tid = data.get('tid', None) if not cid or not tid: raise errors.ValidationError('Requires team and challenge.') challenge = models.Challenge.query.get(data['cid']) team = models.Team.query.get(data['tid']) if not challenge or not team: raise errors.ValidationError('Requires team and challenge.') user = models.User.current() app.challenge_log.info( 'Admin %s <%s> submitting flag for challenge %s <%d>, ' 'team %s <%d>', user.nick, user.email, challenge.name, challenge.cid, team.name, team.tid) try: points = controllers.save_team_answer(challenge, team, None) models.commit() except (errors.IntegrityError, errors.FlushError) as ex: app.logger.exception('Unable to save answer for %s/%s: %s', str(data['tid']), str(data['tid']), str(ex)) models.db.session.rollback() raise errors.AccessDeniedError( 'Unable to save answer for team. See log for details.') cache.delete('cats/%d' % tid) cache.delete('scoreboard') return dict(points=points)
def post(self): tag = models.Tag.create(get_field('name'), get_field('description', '')) models.commit() app.logger.info('Tag %s created by %r.', tag, models.User.current()) cache.clear() return tag
def testGetApiKey(self): key = '44' * 16 self.admin_client.user.api_key = key models.commit() with self.queryLimit(1): resp = self.client.get(self.PATH) self.assert200(resp) self.assertEqual(key, resp.json['api_key'])
def post(self): """Unlock a hint.""" data = flask.request.get_json() hint = controllers.unlock_hint(data['hid']) app.logger.info('Hint %s unlocked by %r.', hint, models.User.current()) models.commit() cache.delete_team('cats/%d') return hint
def delete(self, aid): attachment = models.Attachment.query.get_or_404(aid) #Probably do not need to delete from disk attachment.delete() app.logger.info('Attachment %s deleted by %r.', attachment, models.User.current()) models.commit() cache.clear()
def post(self): cat = models.Category.create( get_field('name'), get_field('description', '')) models.commit() app.logger.info('Category %s created by %r.', cat, models.User.current()) cache.clear() return cat
def testDelete_Own(self): key = '55'*16 self.admin_client.user.api_key = key models.commit() with self.queryLimit(2): resp = self.client.delete(self.PATH + '/' + key) self.assert200(resp) self.assertIsNone(self.admin_client.user.api_key)
def post(self): tag = models.Tag.create( get_field('name'), get_field('description', '')) models.commit() app.logger.info('Tag %s created by %r.', tag, models.User.current()) cache.clear() return tag
def testGetApiKey(self): key = '44'*16 self.admin_client.user.api_key = key models.commit() with self.queryLimit(1): resp = self.client.get(self.PATH) self.assert200(resp) self.assertEqual(key, resp.json['api_key'])
def testDelete_Own(self): key = '55' * 16 self.admin_client.user.api_key = key models.commit() with self.queryLimit(2): resp = self.client.delete(self.PATH + '/' + key) self.assert200(resp) self.assertIsNone(self.admin_client.user.api_key)
def post(self): # TODO: refactor, this is messy raise NotImplementedError('Restore not implemented.') challs = [] models.commit() cache.clear() return {'message': '%d Challenges imported.' % (len(challs),)}
def post(self): # TODO: refactor, this is messy raise NotImplementedError('Restore not implemented.') challs = [] models.commit() cache.clear() return {'message': '%d Challenges imported.' % (len(challs), )}
def post(self): fp = flask.request.files['file'] aid, fpath = attachments.backend.upload(fp) attachment = models.Attachment.query.get(aid) if not attachment: models.Attachment.create(aid, fp.filename, fp.mimetype) models.commit() cache.clear() return dict(aid=aid, fpath=fpath, content_type=fp.mimetype)
def put(self, aid): attachment = models.Attachment.query.get_or_404(aid) attachment.filename = get_field('filename') attachment.set_challenges(get_field('challenges')) app.logger.info('Attachment %s updated by %r.', attachment, models.User.current()) models.commit() cache.clear() return attachment
def put(self, category_slug): category = models.Category.query.get_or_404(category_slug) category.name = get_field('name') category.description = get_field('description', '') app.logger.info('Category %s updated by %r.', category, models.User.current()) models.commit() cache.clear() return self.get_challenges(category)
def post(self): changed = 0 for team in models.Team.query.all(): old = team.score team.update_score() changed += 1 if team.score != old else 0 models.commit() cache.clear() return {'message': ('Recalculated, %d changed.' % changed)}
def put(self, tag_slug): tag = models.Tag.query.get_or_404(tag_slug) tag.name = get_field('name') tag.description = get_field('description', tag.description) app.logger.info('Tag %s updated by %r', tag, models.User.current()) models.commit() cache.clear() return self.get_challenges(tag)
def put(self, category_slug): category = models.Category.query.get_or_404(category_slug) category.name = get_field('name') category.description = get_field('description', category.description) app.logger.info('Category %s updated by %r.', category, models.User.current()) models.commit() cache.clear() return self.get_challenges(category)
def setUp(self): super(NonceValidatorTest, self).setUp() self.chall = models.Challenge.create( 'foo', 'bar', 100, '', unlocked=True, validator='nonce_166432') self.validator = validators.GetValidatorForChallenge(self.chall) self.validator.change_answer('secret123') self.team = models.Team.create('footeam') models.commit()
def register_user(email, nick, password, team_id=None, team_name=None, team_code=None): """Registers a player. Arguments: email: User's email nick: User's nick password: Player's password team_id: Id# of team, or None to create new team. team_name: Name of new team. team_code: Validation code to join team. """ if not re.match(r'[-0-9a-zA-Z.+_]+@[-0-9a-zA-Z.+_]+\.[a-zA-Z]+$', email): raise errors.ValidationError('Invalid email address.') # TODO: Sanitize other fields first = models.User.query.count() == 0 if not first and app.config.get('TEAMS'): if team_id == 'new': try: app.logger.info('Creating new team %s for user %s', team_name, nick) team = models.Team.create(team_name) except exc.IntegrityError: models.db.session.rollback() raise errors.ValidationError('Team already exists!') else: team = models.Team.query.get(int(team_id)) if not team or team_code.lower() != team.code.lower(): raise errors.ValidationError( 'Invalid team selection or team code.') else: team = None try: if not team and not first: team = models.Team.create(nick) user = models.User.create(email, nick, password, team=team) models.commit() except exc.IntegrityError: models.db.session.rollback() if models.User.get_by_email(email): raise errors.ValidationError('Duplicate email address.') if models.User.get_by_nick(nick): raise errors.ValidationError('Duplicate nick.') if team_name and models.Team.get_by_name(team_name): raise errors.ValidationError('Duplicate team name.') raise errors.ValidationError('Unknown integrity error.') if not user.admin: models.ScoreHistory.add_entry(team) models.commit() app.logger.info('User %s <%s> registered from IP %s.', nick, email, flask.request.remote_addr) return user
def put(self, team_id): team = models.Team.query.get_or_404(team_id) app.logger.info('Update of team %r by %r.', team, models.User.current()) data = flask.request.get_json() # Writable fields for field in ('name', 'score'): setattr(team, field, data.get(field, getattr(team, field))) models.commit() cache.delete_team('team/%d') return self._marshal_team(team)
def put(self, team_id): if not utils.access_team(team_id): raise errors.AccessDeniedError('No access to that team.') team = models.Team.query.get_or_404(team_id) data = flask.request.get_json() # Writable fields for field in ('name', 'score'): setattr(team, field, data.get(field, getattr(team, field))) models.commit() return self._marshal_team(team)
def delete(self, keyid=None): if keyid is None: return self._delete_all() user = models.User.current() if keyid != user.api_key: raise errors.AccessDeniedError('Cannot delete that key.') user.api_key = None user.api_key_updated = datetime.datetime.now() models.commit() return dict(status='OK')
def post(self, path): data = flask.request.get_json() page = models.Page.query.get(path) if not page: page = models.Page() models.db.session.add(page) page.title = data.get('title', '') page.contents = data.get('contents', '') models.commit() return page
def delete(self, category_slug): category = models.Category.query.get_or_404(category_slug) try: models.db.session.delete(category) cache.clear() models.commit() except exc.IntegrityError: models.db.session.rollback() raise errors.ValidationError( 'Unable to delete category: make sure it is empty')
def testDelete_All(self): self.admin_client.user.api_key = '55'*16 other_admin = models.User.create('*****@*****.**', 'foo', 'foo') other_admin.promote() other_admin.api_key = '44'*16 models.commit() with self.queryLimit(4): resp = self.client.delete(self.PATH) self.assert200(resp) self.assertIsNone(self.admin_client.user.api_key) self.assertIsNone(other_admin.api_key)
def testDelete_All(self): self.admin_client.user.api_key = '55' * 16 other_admin = models.User.create('*****@*****.**', 'foo', 'foo') other_admin.promote() other_admin.api_key = '44' * 16 models.commit() with self.queryLimit(4): resp = self.client.delete(self.PATH) self.assert200(resp) self.assertIsNone(self.admin_client.user.api_key) self.assertIsNone(other_admin.api_key)
def post(self): app.logger.info('Uploading a new file.') fp = flask.request.files['file'] app.logger.info('Using backend: %r', attachments.backend) aid, fpath = attachments.backend.upload(fp) app.logger.info('File uploaded to backend, got aid %s', aid) attachment = models.Attachment.query.get(aid) if not attachment: models.Attachment.create(aid, fp.filename, fp.mimetype) models.commit() cache.clear() return dict(aid=aid, fpath=fpath, content_type=fp.mimetype)
def post(self): """Register a new user.""" if flask.g.user: raise errors.ValidationError('Cannot register while logged in.') data = flask.request.get_json() user = controllers.register_user(data['email'], data['nick'], data['password'], data.get( 'team_id'), data.get('team_name'), data.get('team_code')) models.commit() flask.session['user'] = user.uid return user