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) 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 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 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 verify_token(self, token, token_type='pwreset'): """Verify a user-specific token.""" token = str(token) decoded = base64.urlsafe_b64decode(token) expires, mac = decoded.split(':') if float(expires) > time.time(): raise errors.ValidationError('Expired token.') expected = self.get_token(token_type=token_type, expires=int(expires)) if not utils.compare_digest(expected, token): raise errors.ValidationError('Invalid token.') return True
def post(self): """Register a new user.""" if utils.is_logged_in(): raise errors.ValidationError('Cannot register while logged in.') data = flask.request.get_json() if not data.get('nick', ''): raise errors.ValidationError('Need a player nick.') if (app.config.get('TEAMS') and not data.get('team_name', '') and not data.get('team_id', 0)): raise errors.ValidationError('Need a team name.') user = auth.register(flask.request) utils.session_for_user(user) return user
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 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', 'unlocked', 'weight'): setattr(challenge, field, data.get(field, getattr(challenge, field))) if 'validator' in data: if not validators.IsValidator(data['validator']): raise errors.ValidationError('Invalid validator.') challenge.validator = data['validator'] 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 get_required_field(name, verbose_name=None): """Retrieve a field or raise an error.""" try: return flask.request.form[name] except KeyError: verbose_name = verbose_name or name raise errors.ValidationError('%s is a required field.' % verbose_name)
def get_field(name, *args): data = flask.request.get_json() try: return data[name] except KeyError: if args: return args[0] raise errors.ValidationError( 'Required field {} not given.'.format(name))
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 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 password2: Validation of 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]{2,4}$', email): raise errors.ValidationError('Invalid email address.') 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) except exc.IntegrityError: models.db.session.rollback() raise errors.ValidationError('Duplicate email/nick.') app.logger.info('User %s <%s> registered from IP %s.', nick, email, flask.request.access_route[0]) return user
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 post(self): """Register a new user.""" if utils.is_logged_in(): raise errors.ValidationError('Cannot register while logged in.') data = flask.request.get_json() if not data.get('nick', ''): raise errors.ValidationError('Need a player nick.') if (app.config.get('TEAMS') and not data.get('team_name', '') and not data.get('team_id', 0)): app.logger.warning('User attempted to register without team.') raise errors.ValidationError('Need a team name.') if (app.config.get('INVITE_KEY') and data.get( 'invite_key', '').strip() != app.config.get('INVITE_KEY')): app.logger.warning( 'Attempted invite-only registration with invalid ' 'invite key: %s', data.get('invite_key', '')) raise errors.ValidationError('Invalid invite key!') app.logger.debug('Passed registration validation for new user.') user = auth.register(flask.request) utils.session_for_user(user) return user
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
def post(self, email): """Verify reset and set new password.""" # TODO: Move to controller data = flask.request.get_json() user = models.User.get_by_email(email) if not user: flask.abort(404) if not user.verify_token(data.get('token', '')): raise errors.AccessDeniedError('Invalid token.') if data['password'] != data['password2']: raise errors.ValidationError("Passwords don't match.") user.set_password(data['password']) models.commit() controllers.user_login(email, data['password']) return {'message': 'Password reset.'}
def post(self, email): """Verify reset and set new password.""" # TODO: Move to controller data = flask.request.get_json() user = models.User.get_by_email(email) if not user: flask.abort(404) token = data.get('token', '') try: user.verify_token(token) except errors.ValidationError as ex: app.logger.warning('Error validating password reset: %s', str(ex)) raise except Exception as ex: app.logger.exception( 'Unhandled exception during password reset: %s', str(ex)) raise if data['password'] != data['password2']: raise errors.ValidationError("Passwords don't match.") user.set_password(data['password']) app.logger.info('Password reset for %r.', user) models.commit() utils.session_for_user(user) return {'message': 'Password reset.'}