Added templates, javascript (jquery), and a cleaning script
parent
10ae797fa5
commit
5faabce182
10
README.md
10
README.md
|
@ -18,7 +18,11 @@ File & Directory Information
|
|||
|
||||
* [`static/`](static/)
|
||||
|
||||
This folder is required by [Flask] and it is where all "static" files live, like things for [CSS] or images or fonts or [HTML] templates.
|
||||
This folder is required by [Flask] and it is where all "static" files live, like things for [CSS] or images or fonts.
|
||||
|
||||
* [`templates/`](templates/)
|
||||
|
||||
This is another folder required by [Flask], and it stores all of the [HTML] code that builds the markup of the website.
|
||||
|
||||
* [`schema.sql`](schema.sql)
|
||||
|
||||
|
@ -33,6 +37,9 @@ File & Directory Information
|
|||
|
||||
This is actual source code of the web application. __! Remember, it is _not_ what you will actually run to deploy the server; the [`setup.sh`](setup.sh) script will take it and configure it, to create a new, functional `server.py` which is what you will run when you deploy.__
|
||||
|
||||
* [`clean.sh`](clean.sh)
|
||||
|
||||
This is just a one-liner script that just gets rid of the created `server.py` and the private keys created for use with [HTTPS].
|
||||
|
||||
|
||||
[Python]: https://www.python.org/
|
||||
|
@ -41,3 +48,4 @@ File & Directory Information
|
|||
[bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell)
|
||||
[CSS]: https://www.w3.org/Style/CSS/Overview.en.html
|
||||
[HTML]: https://en.wikipedia.org/wiki/HTML
|
||||
[HTTPS:]: https://en.wikipedia.org/wiki/HTTPS
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm -f server.py certificate.crt privateKey.key
|
|
@ -12,10 +12,13 @@ from time import sleep
|
|||
|
||||
from uuid import uuid4
|
||||
|
||||
import flag_server
|
||||
|
||||
from passlib.hash import sha256_crypt
|
||||
from contextlib import closing
|
||||
|
||||
flag_rotation_seconds = 60
|
||||
correct_answers = {}
|
||||
|
||||
debug = True
|
||||
|
||||
|
@ -40,6 +43,7 @@ else:
|
|||
# ===========================================================================
|
||||
|
||||
DATABASE = '$DATABASE'
|
||||
CONFIG = '$CONFIGURATION'
|
||||
CERTIFICATE = '$CERTIFICATE_FILE'
|
||||
PRIVATE_KEY = '$PRIVATEKEY_FILE'
|
||||
|
||||
|
@ -49,6 +53,10 @@ if DATABASE == '$DATABASE':
|
|||
error("This server has not yet been configured with a database file!")
|
||||
exit(-1)
|
||||
|
||||
if CONFIG == '$CONFIGURATION':
|
||||
error("This server has not yet been configured with a configuration file!")
|
||||
exit(-1)
|
||||
|
||||
if CERTIFICATE == '$CERTIFICATE_FILE':
|
||||
error("This server has not yet been configured with a certificate!")
|
||||
exit(-1)
|
||||
|
@ -61,6 +69,56 @@ app = Flask( __name__ )
|
|||
|
||||
app.config.from_object(__name__)
|
||||
|
||||
needed_configurations = [
|
||||
"app_title", "app_about", "app_navigation_logged_out",
|
||||
"app_navigation_logged_in", "services"
|
||||
]
|
||||
|
||||
def flag_rotator( services ):
|
||||
global correct_answers
|
||||
|
||||
round = 0
|
||||
while 1:
|
||||
print "FLAG ROUND", round, "="*50
|
||||
correct_answers = {}
|
||||
|
||||
for service in services:
|
||||
flag = flag_server.generate_flag()
|
||||
flag_server.save_flag( flag, "services/" + service['folder_name'] )
|
||||
correct_answers[ flag ] = service['points']
|
||||
|
||||
round += 1
|
||||
sleep( flag_rotation_seconds )
|
||||
|
||||
|
||||
if not ( os.path.exists(CONFIG) ):
|
||||
error("This configuration file '" + CONFIG + "' does not seem to exist!")
|
||||
exit(-1)
|
||||
else:
|
||||
success("The configuration file exists!")
|
||||
handle = open( CONFIG )
|
||||
configuration = json.loads(handle.read().replace("\n","").replace("\t",""))
|
||||
try:
|
||||
for needed_config in needed_configurations:
|
||||
assert configuration[needed_config]
|
||||
except Exception as e:
|
||||
error("Configuration file '" + sys.argv[1] + "' does not have the following configuration tag:")
|
||||
warning(e.message)
|
||||
error("Please fix this and re-run the server.")
|
||||
exit(-1)
|
||||
|
||||
handle.close()
|
||||
|
||||
success("The configuration looks good!")
|
||||
|
||||
success("Starting the flag rotator...")
|
||||
|
||||
flag_rotation = Thread( target = flag_rotator, args = ( configuration['services'],) )
|
||||
flag_rotation.daemon = True
|
||||
flag_rotation.start()
|
||||
|
||||
success("Spinning up the server...")
|
||||
|
||||
def init_db():
|
||||
with closing(connect_db()) as db:
|
||||
with app.open_resource('schema.sql', mode='r') as f:
|
||||
|
@ -80,13 +138,13 @@ def teardown_request(exception):
|
|||
if db is not None:
|
||||
db.close()
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
|
||||
if not ( session['logged_in'] ):
|
||||
return redirect('login')
|
||||
def render( template_name, **kwargs ):
|
||||
return render_template( template_name,
|
||||
app_title = configuration['app_title'],
|
||||
app_navigation_logged_out = configuration['app_navigation_logged_out'],
|
||||
app_navigation_logged_in = configuration['app_navigation_logged_in'],
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
|
@ -108,179 +166,179 @@ def login():
|
|||
|
||||
session_login( request.form['username'] )
|
||||
|
||||
return redirect( "challenges" )
|
||||
|
||||
return render( 'login.html', error = error )
|
||||
|
||||
|
||||
@app.route("/register", methods=["GET", "POST"])
|
||||
def register():
|
||||
|
||||
cur = g.db.execute('select username from users')
|
||||
|
||||
usernames = [row[0] for row in cur.fetchall() ]
|
||||
|
||||
error = ""
|
||||
if request.method == "POST":
|
||||
|
||||
if unicode(request.form['username']) in usernames:
|
||||
error = 'This username is already in use!'
|
||||
elif (request.form['password'] == ""):
|
||||
error = "You must supply a password!"
|
||||
elif request.form['password'] != request.form['confirm']:
|
||||
error = 'Your passwords do not match!'
|
||||
else:
|
||||
|
||||
# I use this for command-line submission...
|
||||
identifier = str(uuid4())
|
||||
|
||||
|
||||
cur = g.db.execute('insert into users (username, password, solved_challenges, score, last_submission, uuid) values ( ?, ?, ?, ?, ?, ? )', [
|
||||
request.form['username'],
|
||||
sha256_crypt.encrypt( request.form['password']),
|
||||
"", # No challenges completed
|
||||
0, # no score.
|
||||
0, # no last submission time,
|
||||
identifier # and a completely unique idenitifier
|
||||
] )
|
||||
|
||||
g.db.commit()
|
||||
|
||||
|
||||
flash("Hello " + request.form['username'] + ", you have successfully registered!")
|
||||
session_login( request.form['username'] )
|
||||
return redirect( "challenges" )
|
||||
|
||||
return render( 'register.html', error = error )
|
||||
|
||||
|
||||
@app.route("/scoreboard")
|
||||
def scoreboard():
|
||||
|
||||
cur = g.db.execute('select username, score from users order by score desc, last_submission asc')
|
||||
response = cur.fetchall()
|
||||
|
||||
users = [ { "username": row[0], "score": row[1] } for row in response]
|
||||
|
||||
return render("scoreboard.html", users = users )
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
|
||||
session_logout()
|
||||
return redirect("about")
|
||||
|
||||
return render_template( 'login.html' )
|
||||
@app.route("/")
|
||||
@app.route("/about")
|
||||
def about(): return render("about.html", app_about=configuration['app_about'])
|
||||
|
||||
@app.route("/challenges")
|
||||
def challenges_page():
|
||||
|
||||
if not ( session['logged_in'] ):
|
||||
return render("login.html", error = "You must log in to be able to see the challenges!")
|
||||
try:
|
||||
cur = g.db.execute('select uuid from users where username =?',
|
||||
[ session['username'],] )
|
||||
|
||||
uuid = cur.fetchone()[0]
|
||||
except Exception as e:
|
||||
print error(e.message)
|
||||
uuid = ''
|
||||
|
||||
return render("challenges.html", challenges = configuration['services'], url=request.url_root, session_value = uuid )
|
||||
|
||||
@app.route("/check_answer", methods=["GET", "POST"])
|
||||
def check_answer():
|
||||
|
||||
global correct_answers
|
||||
|
||||
if request.method == "POST":
|
||||
if request.form['answer'] in session['solved_challenges']:
|
||||
|
||||
return json.dumps({'correct': -1});
|
||||
|
||||
if ( request.form['answer'] in correct_answers.keys() ):
|
||||
|
||||
flag = request.form['answer']
|
||||
|
||||
new_score = int(session['score']) + correct_answers[flag]
|
||||
cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')) where username = (?)", [
|
||||
new_score,
|
||||
session['username']
|
||||
] );
|
||||
|
||||
session['solved_challenges'].append( request.form['answer'] )
|
||||
session['score'] = new_score
|
||||
g.db.commit();
|
||||
|
||||
return json.dumps({'correct': 1, 'new_score': new_score});
|
||||
else:
|
||||
return json.dumps({'correct': 0});
|
||||
|
||||
@app.route("/submit", methods=[ "POST" ])
|
||||
def submit():
|
||||
|
||||
global correct_answers
|
||||
|
||||
if request.method == "POST":
|
||||
|
||||
if ( request.form['flag'] in correct_answers.keys() ):
|
||||
|
||||
flag = request.form['flag']
|
||||
|
||||
cur = g.db.execute('select score, solved_challenges from users where uuid = (?)',
|
||||
[ request.form['uuid'], ])
|
||||
|
||||
|
||||
# @app.route("/register", methods=["GET", "POST"])
|
||||
# def register():
|
||||
current_score, solved_challenges = cur.fetchone()
|
||||
|
||||
# cur = g.db.execute('select username from users')
|
||||
solved_challenges = solved_challenges.split()
|
||||
|
||||
# usernames = [row[0] for row in cur.fetchall() ]
|
||||
if ( flag in solved_challenges ):
|
||||
return 'You already submitted this flag!\n'
|
||||
|
||||
# error = ""
|
||||
# if request.method == "POST":
|
||||
print solved_challenges
|
||||
|
||||
# if unicode(request.form['username']) in usernames:
|
||||
# error = 'This username is already in use!'
|
||||
# elif (request.form['password'] == ""):
|
||||
# error = "You must supply a password!"
|
||||
# elif request.form['password'] != request.form['confirm']:
|
||||
# error = 'Your passwords do not match!'
|
||||
# else:
|
||||
new_score = current_score + correct_answers[flag]
|
||||
solved_challenges.append( flag + " " )
|
||||
cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')), solved_challenges = (?) where uuid = (?)", [
|
||||
new_score,
|
||||
' '.join(solved_challenges),
|
||||
request.form['uuid']
|
||||
] );
|
||||
|
||||
# # I use this for command-line submission...
|
||||
# identifier = str(uuid4())
|
||||
|
||||
|
||||
# cur = g.db.execute('insert into users (username, password, solved_challenges, score, last_submission, uuid) values ( ?, ?, ?, ?, ?, ? )', [
|
||||
# request.form['username'],
|
||||
# sha256_crypt.encrypt( request.form['password']),
|
||||
# "", # No challenges completed
|
||||
# 0, # no score.
|
||||
# 0, # no last submission time,
|
||||
# identifier # and a completely unique idenitifier
|
||||
# ] )
|
||||
|
||||
# g.db.commit()
|
||||
|
||||
|
||||
# flash("Hello " + request.form['username'] + ", you have successfully registered!")
|
||||
# session_login( request.form['username'] )
|
||||
# return redirect( "challenges" )
|
||||
|
||||
# return render( 'register.html', error = error )
|
||||
|
||||
|
||||
# @app.route("/scoreboard")
|
||||
# def scoreboard():
|
||||
|
||||
# cur = g.db.execute('select username, score from users order by score desc, last_submission asc')
|
||||
# response = cur.fetchall()
|
||||
|
||||
# users = [ { "username": row[0], "score": row[1] } for row in response]
|
||||
|
||||
# return render("scoreboard.html", users = users )
|
||||
|
||||
# @app.route("/logout")
|
||||
# def logout():
|
||||
|
||||
# session_logout()
|
||||
# return redirect("about")
|
||||
|
||||
# @app.route("/")
|
||||
# @app.route("/about")
|
||||
# def about(): return render("about.html", app_about=configuration['app_about'])
|
||||
|
||||
# @app.route("/challenges")
|
||||
# def challenges_page():
|
||||
|
||||
# if not ( session['logged_in'] ):
|
||||
# return render("login.html", error = "You must log in to be able to see the challenges!")
|
||||
# try:
|
||||
# cur = g.db.execute('select uuid from users where username =?',
|
||||
# [ session['username'],] )
|
||||
|
||||
# uuid = cur.fetchone()[0]
|
||||
# except Exception as e:
|
||||
# print error(e.message)
|
||||
# uuid = ''
|
||||
|
||||
# return render("challenges.html", challenges = configuration['services'], url=request.url_root, session_value = uuid )
|
||||
|
||||
# @app.route("/check_answer", methods=["GET", "POST"])
|
||||
# def check_answer():
|
||||
|
||||
# global correct_answers
|
||||
|
||||
# if request.method == "POST":
|
||||
# if request.form['answer'] in session['solved_challenges']:
|
||||
|
||||
# return json.dumps({'correct': -1});
|
||||
|
||||
# if ( request.form['answer'] in correct_answers.keys() ):
|
||||
|
||||
# flag = request.form['answer']
|
||||
|
||||
# new_score = int(session['score']) + correct_answers[flag]
|
||||
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')) where username = (?)", [
|
||||
# new_score,
|
||||
# session['username']
|
||||
# ] );
|
||||
|
||||
# session['solved_challenges'].append( request.form['answer'] )
|
||||
# session['score'] = new_score
|
||||
# g.db.commit();
|
||||
# session['solved_challenges'].append( request.form['flag'] )
|
||||
session['score'] = new_score
|
||||
g.db.commit();
|
||||
|
||||
# return json.dumps({'correct': 1, 'new_score': new_score});
|
||||
# else:
|
||||
return 'Correct!\n';
|
||||
else:
|
||||
# return json.dumps({'correct': 0});
|
||||
|
||||
# @app.route("/submit", methods=[ "POST" ])
|
||||
# def submit():
|
||||
|
||||
# global correct_answers
|
||||
|
||||
# if request.method == "POST":
|
||||
|
||||
# if ( request.form['flag'] in correct_answers.keys() ):
|
||||
|
||||
# flag = request.form['flag']
|
||||
|
||||
# cur = g.db.execute('select score, solved_challenges from users where uuid = (?)',
|
||||
# [ request.form['uuid'], ])
|
||||
|
||||
|
||||
# current_score, solved_challenges = cur.fetchone()
|
||||
|
||||
# solved_challenges = solved_challenges.split()
|
||||
|
||||
# if ( flag in solved_challenges ):
|
||||
# return 'You already submitted this flag!\n'
|
||||
|
||||
# print solved_challenges
|
||||
|
||||
# new_score = current_score + correct_answers[flag]
|
||||
# solved_challenges.append( flag + " " )
|
||||
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')), solved_challenges = (?) where uuid = (?)", [
|
||||
# new_score,
|
||||
# ' '.join(solved_challenges),
|
||||
# request.form['uuid']
|
||||
# ] );
|
||||
|
||||
# # session['solved_challenges'].append( request.form['flag'] )
|
||||
# session['score'] = new_score
|
||||
# g.db.commit();
|
||||
|
||||
# # return json.dumps({'correct': 1, 'new_score': new_score});
|
||||
# return 'Correct!\n';
|
||||
# else:
|
||||
# # return json.dumps({'correct': 0});
|
||||
# return 'Incorrect!\n';
|
||||
return 'Incorrect!\n';
|
||||
|
||||
def session_login( username ):
|
||||
|
||||
flash("You were successfully logged in!")
|
||||
|
||||
# cur = g.db.execute('select solved_challenges, score from users where username = (?)',
|
||||
# [username])
|
||||
cur = g.db.execute('select solved_challenges, score from users where username = (?)',
|
||||
[username])
|
||||
|
||||
# solved_challenges, score = cur.fetchone()
|
||||
solved_challenges, score = cur.fetchone()
|
||||
|
||||
session['logged_in'] = True
|
||||
# session['username'] = username
|
||||
# session['score'] = score
|
||||
# session['solved_challenges'] = []
|
||||
session['username'] = username
|
||||
session['score'] = score
|
||||
session['solved_challenges'] = []
|
||||
|
||||
def session_logout():
|
||||
|
||||
flash("You have been successfully logged out.")
|
||||
|
||||
session['logged_in'] = False
|
||||
# session.pop('username')
|
||||
# session.pop('score')
|
||||
session.pop('username')
|
||||
session.pop('score')
|
||||
|
||||
if ( __name__ == "__main__" ):
|
||||
context = (CERTIFICATE, PRIVATE_KEY)
|
||||
|
|
7
setup.sh
7
setup.sh
|
@ -8,7 +8,6 @@
|
|||
|
||||
# Optional variables: this should be modified by the commandline arguments
|
||||
DATABASE=""
|
||||
CONFIGURATION=""
|
||||
|
||||
# Internal variables; do not edit.
|
||||
DEPENDENCIES="python-pip sqlite3 python-flask python-passlib"
|
||||
|
@ -150,12 +149,6 @@ if [ "$DATABASE" == "" ]; then
|
|||
exit -1
|
||||
fi
|
||||
|
||||
# Make sure we entered a configuration file
|
||||
if [ "$CONFIGURATION" == "" ]; then
|
||||
echo "$0: ${RED}you must specify a configuration file!${NC}"
|
||||
display_help
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# This makes it so every function has a "pre-declaration" of all the functions
|
||||
main "$@"
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title> Login -- USCGA BearShop</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/master.css' ) }}">
|
||||
<script src="{{ url_for('static', filename='js/jquery.js' ) }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/notify.js' ) }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/jquery-ui.min.js' ) }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
{% extends "base_page.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div id="login_box_background"></div>
|
||||
<div id="login_box">
|
||||
|
||||
<h1>Welcome the USCGA BearShop!</h1>
|
||||
<p>
|
||||
Please login below with your EDU e-mail and your BearShop password.
|
||||
</p>
|
||||
|
||||
<form>
|
||||
<input type="text" name="email">
|
||||
<input type="password" name="password">
|
||||
<input type="submit" value="LOGIN" id="login">
|
||||
</form>
|
||||
|
||||
|
||||
<span id="register"> REGISTER </span>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title> Login -- USCGA BearShop</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/master.css">
|
||||
<link rel="stylesheet" type="text/css" href="../static/css/master.css">
|
||||
</head>
|
||||
<body>
|
||||
|
Loading…
Reference in New Issue