fluxscoreboard.models

class fluxscoreboard.models.Base(**kwargs)

Base class for all ORM classes. Uses BaseCFG configuration.

class fluxscoreboard.models.BaseCFG[source]

Class that contains custom configuration for a sqlalchemy.ext.declarative.declarative_base() to be used with the ORM. It automatically figures out a tablename (thus no need to set __tablename__).

fluxscoreboard.models.DBSession = <sqlalchemy.orm.scoping.scoped_session object at 0x7f8ad9382c50>

Database session factory. Returns the current threadlocal session.

class fluxscoreboard.models.RootFactory(request)[source]

Skeleton for simple ACL permission protection.

Challenge Models & Functions

class fluxscoreboard.models.challenge.Challenge(**kwargs)[source]

A challenge in the system.

Attributes:

id: The primary key column.

title: Title of the challenge.

text: A description of the challenge.

solution: The challenge’s solution

points: How many points the challenge is worth.

online: Whether the challenge is online.

manual: If the points for this challenge are awareded manually.

category_id: ID of the associated category.

category: Direct access to the Category.

author: A simple string that contains an author (or a list thereof).

dynamic: Whether this challenge is dynamically handled. At the default of False this is just a normal challenge, otherwise, the attribute module must be set.

module: If this challenge is dynamic, it must provide a valid dotted python name for a module that provides the interface for validation and display. The dotted python name given here will be prefixed with fluxscoreboard.dynamic_challenges. from which the module will be loaded and made available on using it.

module: Loads the module from the module name and returns it.

published: Whether the challenge should be displayed in the frontend at all.

points[source]

The points of a challenge which is either the value assigned to it or, if the challenge is manual, the manual_challenge_points object to indicate that the points are manually assigned.

class fluxscoreboard.models.challenge.Category(**kwargs)[source]

A category for challenges.

Attributes:

id: Primary key of category.

name: Name of the category.

challenges: List of challenges in that category.

class fluxscoreboard.models.challenge.Submission(**kwargs)[source]

A single submission. Each entry means that this team has solved the corresponding challenge, i.e. there is no solved flag: The existence of the entry states that.

Attributes:

team_id: Foreign primary key column of the team.

challenge_id: Foreign primary key column of the challenge.

timestamp: A UTC-aware datetime.datetime object. When assigning a value always pass either a timezone-aware object or a naive UTC datetime. Defaults to datetime.datetime.utcnow().

bonus: How many bonus points were awared.

team: Direct access to the team who solved this challenge.

challenge: Direct access to the challenge.

class fluxscoreboard.models.challenge.Feedback(**kwargs)[source]
fluxscoreboard.models.challenge.get_all_challenges()[source]

Return a query that gets all challenges.

fluxscoreboard.models.challenge.get_online_challenges()[source]

Return a query that gets only those challenges that are online.

fluxscoreboard.models.challenge.get_submissions()[source]

Creates a query to eagerly load all submissions. That is, all teams and challenges that are attached to the submissions are fetched with them.

fluxscoreboard.models.challenge.get_all_categories()[source]

Get a list of all available categories.

fluxscoreboard.models.challenge.check_submission(challenge, solution, team, settings)[source]

Check a solution for a challenge submitted by a team and add it to the database if it was correct.

Args:

challenge: An instance of Challenge, the challenge to check the solution for.

solution: A string, the proposed solution for the challenge.

team: Team that submitted the solution.

Returns:
A tuple of (result, msg). result indicates whether the solution was accpeted (and added to the database) or not. The message returns a string with either a result (if result == False) or a congratulations message.
fluxscoreboard.models.challenge.manual_challenge_points = <ManualChallengePoints instance>

A static value that is returned instead of an actual number of points.

fluxscoreboard.models.challenge.update_playing_teams(connection)[source]

Update the number of playing teams whenever it changes.

fluxscoreboard.models.challenge.update_challenge_points(connection, update_team_count=True)[source]

Update the points on each challenge to reflect their current worth.

Country Models & Functions

class fluxscoreboard.models.country.Country(**kwargs)[source]

A country in the database. Basically only a name for different locations of teams.

fluxscoreboard.models.country.get_all_countries()[source]

Get a query that fetches a list of all countries from the database.

News Models & Functions

class fluxscoreboard.models.news.News(**kwargs)[source]

A single announcement, either global or for a challenge, depending on the challenge_id attribute.

Attributes:

id: The primary key.

timestamp: A UTC-aware datetime.datetime object. When assigning a value always pass either a timezone-aware object or a naive UTC datetime. Defaults to datetime.datetime.utcnow().

message: The text of the announcement.

published: Whether the announcement is displayed in the frontend.

challenge_id: If present, which challenge this announcement belongs to.

challenge: Direct access to the challenge, if any.

class fluxscoreboard.models.news.MassMail(**kwargs)[source]

An entry of a mass mail that was sent.

Attributes:

id: The primary key.

timestamp: A UTC-aware datetime.datetime object. When assigning a value always pass either a timezone-aware object or a naive UTC datetime. Defaults to datetime.datetime.utcnow().

subject: The subject of the mail

message: The body of the mail

recipients: A list of recipients that have recieved this mail. Internally this is stored as a json encoded list.

from_: The address which was used as the From: field of the mail.

fluxscoreboard.models.news.get_published_news()[source]

Team Models & Functions

class fluxscoreboard.models.team.Team(**kwargs)[source]

A team represented in the database.

Attributes:

id: Primary key

name: The name of the team.

password: The password of the team. If setting the password, pass it as cleartext. It will automatically be encrypted and stored in the database.

email: E-Mail address of the team. Verified if team is active.

country_id: Foreign Key specifying the location of the team.

local: Whether the team is local at the conference.

token: Token for E-Mail verification.

reset_token: When requesting a new password, this token is used.

challenge_token: Unique token for each team they can provide to
a challenge so this challenge can do rate-limiting or banning or whatever it wants to do.

active: Whether the team’s mail address has been verified and the team can actively log in.

timezone: A timezone, specified as a string, like "Europe/Berlin" or something that, when coerced to unicode, turns out as a string like this. Must be valid timezone.

acatar_filename: The filename under which the avatar is stored in the static/images/avatars directory.

size: The size of the team.

country: Direct access to the teams fluxscoreboard.models.country.Country attribute.

get_solvable_challenges()[source]

Return a list of challenges that the team can solve right now. It returns a list of challenges that are

  • online
  • unsolved by the current team
  • not manual or dynamic (i.e. solvable by entering a solution)
get_unsolved_challenges()[source]

Return a query that produces a list of all unsolved challenges for a given team.

validate_password(password)[source]

Validate the password agains the team. If it matches return True else return False.

fluxscoreboard.models.team.get_all_teams()[source]

Get a query that returns a list of all teams.

fluxscoreboard.models.team.get_active_teams()[source]

Get a query that returns a list of all active teams.

fluxscoreboard.models.team.get_team_solved_subquery(team_id)[source]

Get a query that searches for a submission from a team for a given challenge. The challenge is supposed to come from an outer query.

Example usage:
team_solved_subquery = get_team_solved_subquery(team_id)
challenge_query = (DBSession.query(Challenge,
                                   team_solved_subquery))

In this example we query for a list of all challenges and additionally fetch whether the currenttly logged in team has solved it.

fluxscoreboard.models.team.get_number_solved_subquery()[source]

Get a subquery that returns how many teams have solved a challenge.

Example usage:

number_of_solved_subquery = get_number_solved_subquery()
challenge_query = (DBSession.query(Challenge,
                                   number_of_solved_subquery)

Here we query for a list of all challenges and additionally fetch the number of times it has been solved. This subquery will use the outer challenge to correlate on, so make sure to provide one or this query makes no sense.

fluxscoreboard.models.team.get_team(request)[source]

Get the currently logged in team. Returns None if the team is invalid (e.g. inactive) or noone is logged in or if the scoreboard is in archive mode.

fluxscoreboard.models.team.get_team_by_id(team_id)[source]
fluxscoreboard.models.team.register_team(form, request)[source]

Create a new team from a form and send a confirmation email.

Args:

form: A filled out fluxscoreboard.forms.front.RegisterForm.

request: The corresponding request.

Returns:
The Team that was created.
fluxscoreboard.models.team.send_activation_mail(team, request)[source]

Send activation mail to particular team.

fluxscoreboard.models.team.confirm_registration(token)[source]

For a token, check the database for the corresponding team and activate it if found.

Args:
token: The token that was sent to the user (a string)
Returns:
Either True or False depending on whether the confirmation was successful.
fluxscoreboard.models.team.login(email, password)[source]

Check a combination of credentials for validaity and either return a reason why it failed or return the logged in team.

Args:

email: The email address of the team.

password: The corresponding password.

Returns:
A three-tuple of (result, message, team). result indicates whether the login was successful or not. In case of failure msg contains a reason why it failed so it can be logged (but not printed - we don’t want to give any angle to an attacker). If the login was successful, msg is None. Finally, if the login succeeded, team contains the found instance of Team. If login failed, team is None.
fluxscoreboard.models.team.password_reminder(email, request)[source]

For an email address, find the corresponding team and send a password reset token. If no team is found send an email that no user was found for this address.

fluxscoreboard.models.team.check_password_reset_token(token)[source]

Check if an entered password reset token actually exists in the database.

fluxscoreboard.models.team.TEAM_GROUPS = [u'group:team']

Groups are just fixed: If a team is logged in it belongs to these groups.

fluxscoreboard.models.team.groupfinder(userid, request)[source]

Check if there is a team logged in, and if it is, return the default TEAM_GROUPS.

class fluxscoreboard.models.team.TeamIP(**kwargs)[source]
fluxscoreboard.models.team.update_score(connection, update_all=True)[source]

Update the score of all teams. If update_all is set, the points for all challenges are updated beforehand as well.

This is your one-shot function to create up-to-date points for everything.

Settings Models & Functions

class fluxscoreboard.models.settings.Settings(**kwargs)[source]

Represents application settings. Do not insert rows of this. There must always be only one row which is updated. This is preferred to having multiple rows with only key->value because with this we can enforce types and give an overview over available settings.

The most straightforward usage is calling get() to retrieve the current settings which you can then also edit and they will be saved automatically.

The following settings are available:

submission_disabled: A boolean that describes whether currently submissions are allowed or disabled. Default: False

ctf_start_date: A timezone-aware datetime value that describes when the CTF should start. Before that, the application will behave differently, e.g. may not allow login.

ctf_end_date: When the CTF will end. Same type as ctf_start_date.

ctf_started: This is a property that can only be read and just compares ctf_start_date with the current time to find out whether the CTF has already started or not.

archive_mode: When the scoreboard is in archive mode, the frontend will not allow alteration to the database. Additionally, the whole system is public so everyone can get their solutions checked. This is then verified and the result is returned, but it is not added to the database. The following things will change in archive mode:

  • No registration
  • No login
  • Start / End times ignored
  • Solutions can be submitted but will only return the result, not enter something into the databse
  • Challenges are public in addition to the scoreboard
ctf_state: Which time state the CTF currently is in. Relevant for
permissions etc.

Custom Column Types

class fluxscoreboard.models.types.TZDateTime(*args, **kwargs)[source]

Coerces a tz-aware datetime object into a naive utc datetime object to be stored in the database. If already naive, will keep it.

On return of the data will restore it as an aware object by assuming it is UTC.

Use this instead of the standard sqlalchemy.types.DateTime.

class fluxscoreboard.models.types.Timezone(*args, **kwargs)[source]

Represent a timezone, storing it as a unicode string but giving back a datetime.tzinfo instance.

class fluxscoreboard.models.types.Module(*args, **kwargs)[source]

Represent a python module from the dynamic_challenges submodule. Input is a string but the return value will always be a real python module.