def get_random_round_flag(team_id: int, task_id: int, round: int, current_round: int) -> Optional[helplib.models.Flag]: """Get random flag for team generated for specified round and task :param team_id: team id :param task_id: task id :param round: round to fetch flag for :param current_round: current round :return: Flag mode instance or None if no flag from rounds exist """ with storage.get_redis_storage().pipeline(transaction=True) as pipeline: cache_helper( pipeline=pipeline, cache_key='flags:cached', cache_func=caching.cache_last_flags, cache_args=(current_round, pipeline), ) flags, = pipeline.smembers( f'team:{team_id}:task:{task_id}:round_flags:{round}').execute() try: flag_id = int(secrets.choice(list(flags))) except (ValueError, IndexError, TypeError): return None return get_flag_by_id(flag_id, current_round)
def get_flag_by_field(field_name: str, field_value, round: int) -> helplib.models.Flag: """Get flag by generic field :param field_name: field name to ask cache for :param field_value: value of the field "field_name" to filter on :param round: current round :return: Flag model instance with flag.field_name == field_value :raises: FlagSubmitException if nothing found """ with storage.get_redis_storage().pipeline(transaction=True) as pipeline: cached, = pipeline.exists('flags:cached').execute() if not cached: cache_helper( pipeline=pipeline, cache_key='flags:cached', cache_func=caching.cache_last_flags, cache_args=(round, pipeline), ) pipeline.exists(f'flag:{field_name}:{field_value}') pipeline.get(f'flag:{field_name}:{field_value}') flag_exists, flag_json = pipeline.execute() if not flag_exists: raise helplib.exceptions.FlagSubmitException( 'Flag is invalid or too old') flag = helplib.models.Flag.from_json(flag_json) return flag
def get_tasks() -> List[models.Task]: """Get list of tasks registered in database""" with storage.get_redis_storage().pipeline(transaction=True) as pipeline: cache_helper( pipeline=pipeline, cache_key='tasks:cached', cache_func=caching.cache_tasks, cache_args=(pipeline, ), ) tasks, = pipeline.smembers('tasks').execute() tasks = list(models.Task.from_json(task) for task in tasks) return tasks
def get_teams() -> List[models.Team]: """Get list of teams registered in the database""" with storage.get_redis_storage().pipeline(transaction=True) as pipeline: cache_helper( pipeline=pipeline, cache_key='teams:cached', cache_func=caching.cache_teams, cache_args=(pipeline, ), ) teams, = pipeline.smembers('teams').execute() teams = list(models.Team.from_json(team) for team in teams) return teams
def get_current_global_config() -> models.GlobalConfig: """Get global config from cache is cached, otherwise cache it""" with storage.get_redis_storage().pipeline(transaction=True) as pipeline: cache_helper( pipeline=pipeline, cache_key='global_config:cached', cache_func=storage.caching.cache_global_config, cache_args=(pipeline,), ) result, = pipeline.get('global_config').execute() global_config = models.GlobalConfig.from_json(result) return global_config
def get_team_id_by_token(token: str) -> Optional[int]: """Get team by token :param token: token string :return: team id """ with storage.get_redis_storage().pipeline(transaction=True) as pipeline: cache_helper( pipeline=pipeline, cache_key='teams:cached', cache_func=caching.cache_teams, cache_args=(pipeline, ), ) team_id, = pipeline.get(f'team:token:{token}').execute() try: team_id = int(team_id) except (ValueError, TypeError): return None else: return team_id
def try_add_stolen_flag(flag: helplib.models.Flag, attacker: int, round: int): """Check that flag is valid for current round, add it to cache, then add to db :param flag: Flag model instance :param attacker: attacker team id :param round: current round :raises: an instance of FlagSubmitException on validation error """ game_config = storage.game.get_current_global_config() if round - flag.round > game_config.flag_lifetime: raise helplib.exceptions.FlagSubmitException('Flag is too old') if flag.team_id == attacker: raise helplib.exceptions.FlagSubmitException('Flag is your own') with storage.get_redis_storage().pipeline(transaction=True) as pipeline: # optimization of redis request count cached_stolen = pipeline.exists( f'team:{attacker}:stolen_flags:cached').execute() if not cached_stolen: cache_helper( pipeline=pipeline, cache_key=f'team:{attacker}:stolen_flags:cached', cache_func=caching.cache_last_stolen, cache_args=(attacker, round, pipeline), ) is_new, = pipeline.sadd(f'team:{attacker}:stolen_flags', flag.id).execute() if not is_new: raise helplib.exceptions.FlagSubmitException('Flag already stolen') pipeline.incr(f'team:{attacker}:task:{flag.task_id}:stolen') pipeline.incr(f'team:{flag.team_id}:task:{flag.task_id}:lost') pipeline.execute()