Git Product home page Git Product logo

ctfscoreboard's Introduction

CTF Scoreboard

This is a basic CTF Scoreboard, with support for teams or individual competitors, and a handful of other features.

Copyright 2020 Google LLC. This is not an official Google product.

Author: Please see the AUTHORS file.

This is a version 2.x branch. We've eliminated categories, in favor of tagging challenges. This simplifies the codebase significantly, and is a better fit since so many challenges border on more than one category. However, this branch is not compatible with databases from 1.x. If you need that, check out the 1.x branch, which will only be getting security & bug fixes.

Installation

  1. Install Python with PIP and setuptools. If you'd like to use a virtualenv, set one up and activate it now. Please note that only Python 3.6+ is officially supported at the present time, but it should still work on Python 2.7.

  2. Install the dependencies: pip install -r requirements.txt

  3. Install a database library. For MySQL, consider PyMySQL. For Postgres, use psycopg2. (Others may work; untested.)

  4. Write a config.py for your relevant installation. An example is provided in config.example.py.

     SQLALCHEMY_DATABASE_URI = 'mysql://username:password@server/db'
     #SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://username:password@server/db'
     SECRET_KEY = 'Some Random Value For Session Keys'
     TEAM_SECRET_KEY = 'Another Random Value For Team Invite Codes'
     TITLE = 'FakeCTF'
     TEAMS = True
     ATTACHMENT_DIR = 'attachments'
     LOGIN_METHOD = 'local'  # or appengine
    

If you are using plaintext HTTP to run your scoreboard, you will need to add the following to your config.py, so that cookies will work:

    SESSION_COOKIE_SECURE = False

If you are developing the scoreboard, the following settings may be useful for debugging purposes. Not useful for production usage, however.

    COUNT_QUERIES = True
    SQLALCHEMY_ECHO = True
  1. Create the database:

     python main.py createdb
    
  2. Set up your favorite python application server, optionally behind a webserver. You'll want to use main.app as your WSGI handler. Tested with uwsgi + nginx. Not tested with anything else, let me know if you have success. Sample configs are in doc/.

  3. Register a user. The first user registed is automatically made an admin. You probably want to register your user before your players get access.

  4. Have fun! Maybe set up some challenges. Players might like that more.

Installation using Docker

  1. Navigate to the folder where the Dockerfile is located.

  2. Run the command below to build a docker image for the scoreboard and tag it as "scoreboard".

    docker build -t "scoreboard" .
    
  3. Run the command below to create the docker container.

    docker create -p 80:80 scoreboard
    
  4. Find the name of the container you created for the scoreboard.

    docker container ls -a
    
  5. Run the command below to start the docker container for the scoreboard.

    docker start "container_name"
    

Options

SCORING: Set to 'progressive' to enable a scoring system where the total points for each challenge are divided amongst all the teams that solve that challenge. This rewards teams that solve infrequently solved (hard or obscure) challenges.

TITLE: Scoreboard page titles.

TEAMS: True if teams should be used, False for each player on their own team.

SQLALCHEMY_DATABASE_URI: A SQLAlchemy database URI string.

LOGIN_METHOD: Supports 'local'

Development

Build Status codecov

Use hooks

ln -s ../../.hooks/pre-commit.sh .git/hooks/pre-commit

Test Cases

  • Setup database
  • Create user, verify admin
  • Create challenge
    • With, without attachment
  • Edit challenges
    • Add attachment
    • Delete attachment
  • Download backup
  • Restore backup
  • Create 2nd user, verify not admin
    • Solve challenge
    • Download attachment

Thanks

This project stands on the shoulders of giants. A big thanks to the following projects used to build this:

And many more indirect dependencies.

ctfscoreboard's People

Contributors

adamchainz avatar jonzeolla avatar k9delight avatar m0x40 avatar matir avatar n1ruragu avatar nragupathy avatar x64x6a avatar zwade avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ctfscoreboard's Issues

Reset password fails with Internal Server Error. No SMTP server

This should be a configurable option. No SMTP server? Then no password reset button for example. Alternatively you can require a SMTP server to operate.

  File "/home/kristoffer/code/ctfscoreboard/scoreboard/mail.py", line 35, in send
    server = smtplib.SMTP(host)

^ that is the line where a change would be needed.

Deprecation Warnings

/usr/local/google/home/zwade/Documents/scoreboard/local/lib/python2.7/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.sqlalchemy is deprecated, use flask_sqlalchemy instead.
  .format(x=modname), ExtDeprecationWarning
/usr/local/google/home/zwade/Documents/scoreboard/local/lib/python2.7/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.restful is deprecated, use flask_restful instead.
  .format(x=modname), ExtDeprecationWarning
/usr/local/google/home/zwade/Documents/scoreboard/local/lib/python2.7/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.restful.fields is deprecated, use flask_restful.fields instead.
  .format(x=modname), ExtDeprecationWarning

Error on promoting user to admin

I have a game set up with Teams disabled. Another user created an account and registered and I wanted to set them up as an admin. Attempting to do so gave me an Internal Server Error. The logs showed this error:

[2016-07-20 20:20:59,843] ERROR in app: Exception on /api/users/2 [PUT]
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 477, in wrapper
    resp = resource(*args, **kwargs)
  File "./scoreboard/utils.py", line 54, in wrapper
    return f(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 587, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 679, in wrapper
    resp = f(*args, **kwargs)
  File "./scoreboard/rest.py", line 138, in put
    user.team.name = data['nick']
AttributeError: 'NoneType' object has no attribute 'name'

Utilitize HTTP caching for API resources

We should be able to use HTTP Etags for API resources to reduce bandwidth.

Taking an etag from the client and comparing memcache.get(resource_type_md5) gives us the ability to quickly identify if the data has changed, and if to return the new results, alternatively send a 304 not modified if unchanged.

Benefits: bandwidth saved, maybe reduced CPU time?

Costs: more code paths added to the application

No clear consensus if this is worthwhile implementing vs adding other functionality.

Design/CSS issues

There seems to be a few CSS issues, here in Chrome Version 50.0.2661.75 (64-bit) on Ubuntu.

The content disappears under the top bar.

2016-06-16-151241_1073x364_scrot

It would also be nice for usability if the "Title" logo was clickable and lead to /

Support for many to many attachments

To quote from: Matir/pwnableweb-scoreboard#89

"Complexity: Deleting one attachment from one challenge - do we cascade delete? leave them as is?"

It might be worthwhile having a new admin section called "Attachments" where admins can upload new files, and then having a drop down style box.

For orphaned files - this could be identified by having the number of links to the attachment displayed - ala foo.zip (1) vs bar.zip (0)

Remove Support for Hints

It's not being used, causes overhead both in processing and development, and is hard to reasonably implement for online CTFs.

Problem trying out the project: Foreign key constraint fails

I just did the basic install/setup to try this out, and happened to have a MariaDB server running (mysql) so I thought I'd try that.

I get the following error trying to add a challenge

Traceback (most recent call last):
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 268, in error_router
    return self.handle_error(e)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 268, in error_router
    return self.handle_error(e)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 477, in wrapper
    resp = resource(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/scoreboard/utils.py", line 46, in wrapper
    return f(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/scoreboard/utils.py", line 62, in wrapper
    return f(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 587, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 679, in wrapper
    resp = f(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/scoreboard/rest.py", line 467, in post
    models.commit()
  File "/home/kristoffer/code/ctfscoreboard/scoreboard/models.py", line 702, in commit
    db.session.commit()
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 157, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 801, in commit
    self.transaction.commit()
File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 392, in commit
    self._prepare_impl()
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 372, in _prepare_impl
    self.session.flush()
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2019, in flush
    self._flush(objects)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2137, in _flush
    transaction.rollback(_capture_exception=True)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2101, in _flush
    flush_context.execute()
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
    rec.execute(self)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
    uow
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 174, in save_obj
    mapper, table, insert)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 767, in _emit_insert_statements
    execute(statement, multiparams)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute
    return meth(self, multiparams, params)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
    compiled_sql, distilled_params
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1146, in _execute_context
    context)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1341, in _handle_dbapi_exception
    exc_info
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 202, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_context
    context)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 450, in do_execute
    cursor.execute(statement, parameters)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File "/home/kristoffer/code/ctfscoreboard/venv/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
IntegrityError: (_mysql_exceptions.IntegrityError) (1452, 'Cannot add or update a child row: a foreign key constraint fails (`ctfscoreboard`.`challenge`, CONSTRAINT `challenge_ibfk_1` FOREIGN KEY (`cat_slug`) REFERENCES `category` (`slug`))') [SQL: u'INSERT INTO challenge (cid, name, description, points, answer_hash, unlocked, weight, prerequisite, cat_slug) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)'] [parameters: (209040478714093, 'Test challenge', 'What is the answer to the ultimate question?', 42, '$p5k2$$8Gozsv/M$2PxSZx6pwqdfI6uzqwjdnhotEXwHqs2a', 1, 1, '', '42')]

Posting here before I start digging through the code, in case this is something you are aware of. :-)

Optimize .current()

Optimize Team.current() and User.current() to perform only a single query in either case or use of both.

Fix scrollbar jumping around

When angular reconstructs the DOM, the scrollbar will often disappear and reappear, causing an annoying jerk.

Allow users to change teams

To quote,

"""
Other complexities:

What about after the game has started?
What happens to the newly-empty team, if applicable?
Is there metadata tied to a team that should be tied to players?
"""

To avoid any surprises (such as db corruption, etc) for admins, we won't allow changes after the game has started - players can create a new account then.

If the team is empty - delete applicable records. Since the game will not have started yet, there won't be any score history to cascade delete, etc.

As for meta data issues - I'll leave that up for investigation.

Add solves information to /api/scoreboard for each team

It would be easier to write a chatter bot if the /api/scoreboard endpoint returned solved information (similar to /api/categories) - as we could then report on ladder changes, when challenges were solved by who, etc.

(additionally, it means not having to mess around with /api/categories which doesn't allow anonymous access).

Category queries request each hint individually

Makes a large number of requests of the form

SELECT unlocked_hint.hint_hid AS unlocked_hint_hint_hid, unlocked_hint.team_tid AS unlocked_hint_team_tid, unlocked_hint.timestamp AS unlocked_hint_timestamp, unlocked_hint.src_ip AS unlocked_hint_src_ip, hint_1.hid AS hint_1_hid, hint_1.challenge_cid AS hint_1_challenge_cid, hint_1.hint AS hint_1_hint, hint_1.cost AS hint_1_cost 
FROM unlocked_hint LEFT OUTER JOIN hint AS hint_1 ON hint_1.hid = unlocked_hint.hint_hid 
WHERE unlocked_hint.hint_hid = ? AND unlocked_hint.team_tid = ?

Allow team names to be changed

The player who registered a team (lowest ID belonging to that team) should be able to change the team name. This will cut back on the occasional support request to game admins.

Renaming the team should be available to admins as well.

Should probably be only possible before game starts.

Challenge identifiers should be UUID's

k9delight:

If challenge identifiers were UUID's, it would give us a variety of features, such as:

  • the ability to incrementally add levels and merge/restore them without likelyhood of conflict with existing levels
  • "level packs" where we can distribute the level descriptions afterwards, and people can add them to their own instance

matir:

I completely agree, but more so, I think we should do the same for:

  • Categories (or possibly deterministic keys for merging)
  • Hints

Basically anything that's attached to the Challenges.

from: Matir/pwnableweb-scoreboard#81

Change dependency handling

  • Using JSON isn't ideal, should ideally by based using database structure.
  • Time release system should be handled by a dependency system.
  • Challenges should have an indicator saying they were recently released, etc.

Cookie / team_tid invalidation

With #75 merged, it introduces a "feature" where users who change teams now are in possession of cookies that have team_tid for both teams (before/after cookie).

There was some discussion in the pull request about best way of handling it.

Add common tests

Build common tests to be included in test cases:

  • If a single REST request results in >5 queries, fail.

/api/page/home returns 404 and invalid JSON

A GET to /api/page/home returns

)]}',
{
    "message": "The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again."
}

Notice the weird looking )]}', before the JSON object.

/api/categories appears to do a N+1 based on team count

Debug statements:

2016-06-09 09:10:59,794 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,794 INFO sqlalchemy.engine.base.Engine (103835647613876, 4)
2016-06-09 09:10:59,797 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,797 INFO sqlalchemy.engine.base.Engine (262102324824167, 4)
2016-06-09 09:10:59,800 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,800 INFO sqlalchemy.engine.base.Engine (262102324824167, 4)
2016-06-09 09:10:59,804 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,804 INFO sqlalchemy.engine.base.Engine (262102324824167, 4)
2016-06-09 09:10:59,809 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,809 INFO sqlalchemy.engine.base.Engine (253824321431412, 4)
2016-06-09 09:10:59,812 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,812 INFO sqlalchemy.engine.base.Engine (253824321431412, 4)
2016-06-09 09:10:59,817 INFO sqlalchemy.engine.base.Engine SELECT count(*) AS count_1
FROM (SELECT answer.challenge_cid AS answer_challenge_cid, answer.team_tid AS answer_team_tid, answer.timestamp AS answer_timestamp, answer.answer_hash AS answer_answer_hash, answer.submit_ip AS answer_submit_ip, answer.first_blood AS answer_first_blood
FROM answer
WHERE ? = answer.challenge_cid AND ? = answer.team_tid) AS anon_1
2016-06-09 09:10:59,817 INFO sqlalchemy.engine.base.Engine (253824321431412, 4)
2016-06-09 09:10:59,819 INFO sqlalchemy.engine.base.Engine SELECT team.tid AS team_tid, team.name AS team_name, team.score AS team_score, team.last_solve AS team_last_solve
FROM team
WHERE team.tid = ?
2016-06-09 09:10:59,819 INFO sqlalchemy.engine.base.Engine (2,)
2016-06-09 09:10:59,821 INFO sqlalchemy.engine.base.Engine SELECT team.tid AS team_tid, team.name AS team_name, team.score AS team_score, team.last_solve AS team_last_solve
FROM team
WHERE team.tid = ?
2016-06-09 09:10:59,821 INFO sqlalchemy.engine.base.Engine (7,)
2016-06-09 09:10:59,822 INFO sqlalchemy.engine.base.Engine SELECT team.tid AS team_tid, team.name AS team_name, team.score AS team_score, team.last_solve AS team_last_solve
FROM team
WHERE team.tid = ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.