mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 05:54:19 +01:00
Testing branch (#211)
* Extracting key checking logic to make it more extensible * Add missing keys __init__ file * Adding logging access and errors to Dockerfile * Use template inheritance for page.html (#198) * Fix exception on cofirmation screen (#202) When a user attempts to confirm an e-mail address, an exception is thrown because the db session is closed prior to logging. The line db.session.close() has to move after the logging, otherwise the team parameters from the orm object are discarded and an exception is thrown. Closing the session after logging, fixes the issue. * Adding custom key types for challenges * Separating out admin.py, adding challenge types * Don't let truncate affect edit modal * File uploads no longer refresh page (#207) Closes (#180) * Fixing missing import * Fixing mistake in flag JSON response * Removing compare_digest to support Python 2.7.6 * Fixing inconsistencies in standard challenge modal * Passing submission input over to template js * Handling cases where data can't be found in the DOM better * Don't refresh modal if it's just a refresh operation * Fixing solving challenges while scoreboard is public Induce a redirect to make user login * Adding missing js file and fixing migration * Fixing some visual glitches and streamlining challenge creation
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""Adds challenge types and uses keys table
|
||||
|
||||
Revision ID: 87733981ca0e
|
||||
Revises: cb3cfcc47e2f
|
||||
Create Date: 2017-02-04 14:50:16.999303
|
||||
|
||||
"""
|
||||
from CTFd.models import db, Challenges, Keys
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.sql import text, table, column
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
import json
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '87733981ca0e'
|
||||
down_revision = 'cb3cfcc47e2f'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
keys_table = table('keys',
|
||||
column('id', db.Integer),
|
||||
column('chal', db.Integer),
|
||||
column('key_type', db.Integer),
|
||||
column('flag', db.Text)
|
||||
)
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
|
||||
## Copy over flags data to Keys table
|
||||
print "Getting bind..."
|
||||
conn = op.get_bind()
|
||||
|
||||
print "Executing: SELECT id, flags from challenges"
|
||||
res = conn.execute(text("SELECT id, flags from challenges"))
|
||||
results = res.fetchall()
|
||||
|
||||
print "There are {} results".format(len(results))
|
||||
new_keys = []
|
||||
print "Processing existing flags"
|
||||
for r in results:
|
||||
if r[1]: ## Check if flags are NULL
|
||||
data = json.loads(r[1])
|
||||
for old_keys in data:
|
||||
new_keys.append({'chal':r[0], 'flag':old_keys.get('flag'), 'key_type':old_keys.get('type')})
|
||||
if new_keys:
|
||||
## Base CTFd databases actually already insert into Keys but the database does not make use of them
|
||||
## This prevents duplicate entries of keys
|
||||
print "Executing: TRUNCATE keys"
|
||||
conn.execute(text("TRUNCATE `keys`"))
|
||||
|
||||
print "Bulk inserting the keys"
|
||||
op.bulk_insert(keys_table, new_keys)
|
||||
|
||||
## Add type column to challenges
|
||||
print "Adding type column to challenges"
|
||||
op.add_column('challenges', sa.Column('type', sa.Integer(), nullable=True, default=0))
|
||||
|
||||
## Set all NULLs to 0
|
||||
print "Setting all NULLs to 0"
|
||||
conn.execute("UPDATE challenges set type=0 WHERE type IS NULL")
|
||||
|
||||
## Drop flags from challenges
|
||||
print "Dropping flags column from challenges"
|
||||
op.drop_column('challenges', 'flags')
|
||||
|
||||
print "Finished"
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
print "Getting bind..."
|
||||
conn = op.get_bind()
|
||||
|
||||
print "Adding flags column back to challenges table"
|
||||
op.add_column('challenges', sa.Column('flags', sa.TEXT(), nullable=True))
|
||||
|
||||
print "Dropping type column from challenges table"
|
||||
op.drop_column('challenges', 'type')
|
||||
|
||||
print "Executing: SELECT id, flags from challenges"
|
||||
res = conn.execute("SELECT id, flags from challenges")
|
||||
results = res.fetchall()
|
||||
|
||||
print "There are {} results".format(len(results))
|
||||
for chal_id in results:
|
||||
new_keys = Keys.query.filter_by(chal=chal_id[0]).all()
|
||||
old_flags = []
|
||||
for new_key in new_keys:
|
||||
flag_dict = {'flag': new_key.flag, 'type': new_key.key_type}
|
||||
old_flags.append(flag_dict)
|
||||
old_flags =json.dumps(old_flags)
|
||||
print "Updating challenge {} to insert {}".format(chal_id[0], flag_dict)
|
||||
conn.execute(text('UPDATE challenges SET flags=:flags WHERE id=:id'), id=chal_id[0], flags=old_flags)
|
||||
|
||||
print "Finished"
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Add data column to keys table
|
||||
|
||||
Revision ID: a4e30c94c360
|
||||
Revises: 87733981ca0e
|
||||
Create Date: 2017-02-13 21:43:46.929248
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a4e30c94c360'
|
||||
down_revision = '87733981ca0e'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('keys', sa.Column('data', sa.Text(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('keys', 'data')
|
||||
# ### end Alembic commands ###
|
||||
@@ -1,148 +0,0 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: cb3cfcc47e2f
|
||||
Revises:
|
||||
Create Date: 2017-01-17 15:39:42.804290
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'cb3cfcc47e2f'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('challenges',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=80), nullable=True),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('value', sa.Integer(), nullable=True),
|
||||
sa.Column('category', sa.String(length=80), nullable=True),
|
||||
sa.Column('flags', sa.Text(), nullable=True),
|
||||
sa.Column('hidden', sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('config',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('key', sa.Text(), nullable=True),
|
||||
sa.Column('value', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('containers',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=80), nullable=True),
|
||||
sa.Column('buildfile', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('pages',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('route', sa.String(length=80), nullable=True),
|
||||
sa.Column('html', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('route')
|
||||
)
|
||||
op.create_table('teams',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=128), nullable=True),
|
||||
sa.Column('email', sa.String(length=128), nullable=True),
|
||||
sa.Column('password', sa.String(length=128), nullable=True),
|
||||
sa.Column('website', sa.String(length=128), nullable=True),
|
||||
sa.Column('affiliation', sa.String(length=128), nullable=True),
|
||||
sa.Column('country', sa.String(length=32), nullable=True),
|
||||
sa.Column('bracket', sa.String(length=32), nullable=True),
|
||||
sa.Column('banned', sa.Boolean(), nullable=True),
|
||||
sa.Column('verified', sa.Boolean(), nullable=True),
|
||||
sa.Column('admin', sa.Boolean(), nullable=True),
|
||||
sa.Column('joined', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('email'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('awards',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('teamid', sa.Integer(), nullable=True),
|
||||
sa.Column('name', sa.String(length=80), nullable=True),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.Column('value', sa.Integer(), nullable=True),
|
||||
sa.Column('category', sa.String(length=80), nullable=True),
|
||||
sa.Column('icon', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['teamid'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('files',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chal', sa.Integer(), nullable=True),
|
||||
sa.Column('location', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chal'], ['challenges.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('keys',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chal', sa.Integer(), nullable=True),
|
||||
sa.Column('key_type', sa.Integer(), nullable=True),
|
||||
sa.Column('flag', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chal'], ['challenges.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('solves',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chalid', sa.Integer(), nullable=True),
|
||||
sa.Column('teamid', sa.Integer(), nullable=True),
|
||||
sa.Column('ip', sa.Integer(), nullable=True),
|
||||
sa.Column('flag', sa.Text(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chalid'], ['challenges.id'], ),
|
||||
sa.ForeignKeyConstraint(['teamid'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('chalid', 'teamid')
|
||||
)
|
||||
op.create_table('tags',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chal', sa.Integer(), nullable=True),
|
||||
sa.Column('tag', sa.String(length=80), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chal'], ['challenges.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('tracking',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('ip', sa.BigInteger(), nullable=True),
|
||||
sa.Column('team', sa.Integer(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['team'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('wrong_keys',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chalid', sa.Integer(), nullable=True),
|
||||
sa.Column('teamid', sa.Integer(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.Column('flag', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chalid'], ['challenges.id'], ),
|
||||
sa.ForeignKeyConstraint(['teamid'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('wrong_keys')
|
||||
op.drop_table('tracking')
|
||||
op.drop_table('tags')
|
||||
op.drop_table('solves')
|
||||
op.drop_table('keys')
|
||||
op.drop_table('files')
|
||||
op.drop_table('awards')
|
||||
op.drop_table('teams')
|
||||
op.drop_table('pages')
|
||||
op.drop_table('containers')
|
||||
op.drop_table('config')
|
||||
op.drop_table('challenges')
|
||||
# ### end Alembic commands ###
|
||||
174
migrations/versions/cb3cfcc47e2f_base.py
Normal file
174
migrations/versions/cb3cfcc47e2f_base.py
Normal file
@@ -0,0 +1,174 @@
|
||||
"""Base 1.0.0 CTFd database
|
||||
|
||||
Revision ID: cb3cfcc47e2f
|
||||
Revises:
|
||||
Create Date: 2017-01-17 15:39:42.804290
|
||||
|
||||
"""
|
||||
from CTFd import create_app
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'cb3cfcc47e2f'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
app = create_app()
|
||||
engine = sa.create_engine(app.config.get('SQLALCHEMY_DATABASE_URI'))
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
if not engine.dialect.has_table(engine, 'challenges'):
|
||||
op.create_table('challenges',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=80), nullable=True),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('value', sa.Integer(), nullable=True),
|
||||
sa.Column('category', sa.String(length=80), nullable=True),
|
||||
sa.Column('flags', sa.Text(), nullable=True),
|
||||
sa.Column('hidden', sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'config'):
|
||||
op.create_table('config',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('key', sa.Text(), nullable=True),
|
||||
sa.Column('value', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'containers'):
|
||||
op.create_table('containers',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=80), nullable=True),
|
||||
sa.Column('buildfile', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'pages'):
|
||||
op.create_table('pages',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('route', sa.String(length=80), nullable=True),
|
||||
sa.Column('html', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('route')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'teams'):
|
||||
op.create_table('teams',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=128), nullable=True),
|
||||
sa.Column('email', sa.String(length=128), nullable=True),
|
||||
sa.Column('password', sa.String(length=128), nullable=True),
|
||||
sa.Column('website', sa.String(length=128), nullable=True),
|
||||
sa.Column('affiliation', sa.String(length=128), nullable=True),
|
||||
sa.Column('country', sa.String(length=32), nullable=True),
|
||||
sa.Column('bracket', sa.String(length=32), nullable=True),
|
||||
sa.Column('banned', sa.Boolean(), nullable=True),
|
||||
sa.Column('verified', sa.Boolean(), nullable=True),
|
||||
sa.Column('admin', sa.Boolean(), nullable=True),
|
||||
sa.Column('joined', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('email'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'awards'):
|
||||
op.create_table('awards',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('teamid', sa.Integer(), nullable=True),
|
||||
sa.Column('name', sa.String(length=80), nullable=True),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.Column('value', sa.Integer(), nullable=True),
|
||||
sa.Column('category', sa.String(length=80), nullable=True),
|
||||
sa.Column('icon', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['teamid'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'files'):
|
||||
op.create_table('files',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chal', sa.Integer(), nullable=True),
|
||||
sa.Column('location', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chal'], ['challenges.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'keys'):
|
||||
op.create_table('keys',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chal', sa.Integer(), nullable=True),
|
||||
sa.Column('key_type', sa.Integer(), nullable=True),
|
||||
sa.Column('flag', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chal'], ['challenges.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'solves'):
|
||||
op.create_table('solves',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chalid', sa.Integer(), nullable=True),
|
||||
sa.Column('teamid', sa.Integer(), nullable=True),
|
||||
sa.Column('ip', sa.Integer(), nullable=True),
|
||||
sa.Column('flag', sa.Text(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chalid'], ['challenges.id'], ),
|
||||
sa.ForeignKeyConstraint(['teamid'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('chalid', 'teamid')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'tags'):
|
||||
op.create_table('tags',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chal', sa.Integer(), nullable=True),
|
||||
sa.Column('tag', sa.String(length=80), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chal'], ['challenges.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'tracking'):
|
||||
op.create_table('tracking',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('ip', sa.BigInteger(), nullable=True),
|
||||
sa.Column('team', sa.Integer(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['team'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
if not engine.dialect.has_table(engine, 'wrong_keys'):
|
||||
op.create_table('wrong_keys',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('chalid', sa.Integer(), nullable=True),
|
||||
sa.Column('teamid', sa.Integer(), nullable=True),
|
||||
sa.Column('date', sa.DateTime(), nullable=True),
|
||||
sa.Column('flag', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['chalid'], ['challenges.id'], ),
|
||||
sa.ForeignKeyConstraint(['teamid'], ['teams.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('wrong_keys')
|
||||
op.drop_table('tracking')
|
||||
op.drop_table('tags')
|
||||
op.drop_table('solves')
|
||||
op.drop_table('keys')
|
||||
op.drop_table('files')
|
||||
op.drop_table('awards')
|
||||
op.drop_table('teams')
|
||||
op.drop_table('pages')
|
||||
op.drop_table('containers')
|
||||
op.drop_table('config')
|
||||
op.drop_table('challenges')
|
||||
# ### end Alembic commands ###
|
||||
Reference in New Issue
Block a user