Added templates, javascript (jquery), and a cleaning script

master
John Hammond 2016-08-17 11:15:05 -04:00
parent 10ae797fa5
commit 5faabce182
10 changed files with 251 additions and 127 deletions

View File

@ -18,7 +18,11 @@ File & Directory Information
* [`static/`](static/) * [`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) * [`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.__ 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/ [Python]: https://www.python.org/
@ -41,3 +48,4 @@ File & Directory Information
[bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell) [bash]: https://en.wikipedia.org/wiki/Bash_(Unix_shell)
[CSS]: https://www.w3.org/Style/CSS/Overview.en.html [CSS]: https://www.w3.org/Style/CSS/Overview.en.html
[HTML]: https://en.wikipedia.org/wiki/HTML [HTML]: https://en.wikipedia.org/wiki/HTML
[HTTPS:]: https://en.wikipedia.org/wiki/HTTPS

3
clean.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
rm -f server.py certificate.crt privateKey.key

View File

@ -12,10 +12,13 @@ from time import sleep
from uuid import uuid4 from uuid import uuid4
import flag_server
from passlib.hash import sha256_crypt from passlib.hash import sha256_crypt
from contextlib import closing from contextlib import closing
flag_rotation_seconds = 60
correct_answers = {}
debug = True debug = True
@ -40,6 +43,7 @@ else:
# =========================================================================== # ===========================================================================
DATABASE = '$DATABASE' DATABASE = '$DATABASE'
CONFIG = '$CONFIGURATION'
CERTIFICATE = '$CERTIFICATE_FILE' CERTIFICATE = '$CERTIFICATE_FILE'
PRIVATE_KEY = '$PRIVATEKEY_FILE' PRIVATE_KEY = '$PRIVATEKEY_FILE'
@ -49,6 +53,10 @@ if DATABASE == '$DATABASE':
error("This server has not yet been configured with a database file!") error("This server has not yet been configured with a database file!")
exit(-1) exit(-1)
if CONFIG == '$CONFIGURATION':
error("This server has not yet been configured with a configuration file!")
exit(-1)
if CERTIFICATE == '$CERTIFICATE_FILE': if CERTIFICATE == '$CERTIFICATE_FILE':
error("This server has not yet been configured with a certificate!") error("This server has not yet been configured with a certificate!")
exit(-1) exit(-1)
@ -61,6 +69,56 @@ app = Flask( __name__ )
app.config.from_object(__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(): def init_db():
with closing(connect_db()) as db: with closing(connect_db()) as db:
with app.open_resource('schema.sql', mode='r') as f: with app.open_resource('schema.sql', mode='r') as f:
@ -80,13 +138,13 @@ def teardown_request(exception):
if db is not None: if db is not None:
db.close() db.close()
# -------------------------------------------------------------------- def render( template_name, **kwargs ):
return render_template( template_name,
@app.route("/") app_title = configuration['app_title'],
def index(): app_navigation_logged_out = configuration['app_navigation_logged_out'],
app_navigation_logged_in = configuration['app_navigation_logged_in'],
if not ( session['logged_in'] ): **kwargs
return redirect('login') )
@app.route("/login", methods=["GET", "POST"]) @app.route("/login", methods=["GET", "POST"])
def login(): def login():
@ -108,179 +166,179 @@ def login():
session_login( request.form['username'] ) session_login( request.form['username'] )
return redirect( "about" ) return redirect( "challenges" )
return render_template( 'login.html' ) return render( 'login.html', error = error )
# @app.route("/register", methods=["GET", "POST"]) @app.route("/register", methods=["GET", "POST"])
# def register(): def register():
# cur = g.db.execute('select username from users') cur = g.db.execute('select username from users')
# usernames = [row[0] for row in cur.fetchall() ] usernames = [row[0] for row in cur.fetchall() ]
# error = "" error = ""
# if request.method == "POST": if request.method == "POST":
# if unicode(request.form['username']) in usernames: if unicode(request.form['username']) in usernames:
# error = 'This username is already in use!' error = 'This username is already in use!'
# elif (request.form['password'] == ""): elif (request.form['password'] == ""):
# error = "You must supply a password!" error = "You must supply a password!"
# elif request.form['password'] != request.form['confirm']: elif request.form['password'] != request.form['confirm']:
# error = 'Your passwords do not match!' error = 'Your passwords do not match!'
# else: else:
# # I use this for command-line submission... # I use this for command-line submission...
# identifier = str(uuid4()) identifier = str(uuid4())
# cur = g.db.execute('insert into users (username, password, solved_challenges, score, last_submission, uuid) values ( ?, ?, ?, ?, ?, ? )', [ cur = g.db.execute('insert into users (username, password, solved_challenges, score, last_submission, uuid) values ( ?, ?, ?, ?, ?, ? )', [
# request.form['username'], request.form['username'],
# sha256_crypt.encrypt( request.form['password']), sha256_crypt.encrypt( request.form['password']),
# "", # No challenges completed "", # No challenges completed
# 0, # no score. 0, # no score.
# 0, # no last submission time, 0, # no last submission time,
# identifier # and a completely unique idenitifier identifier # and a completely unique idenitifier
# ] ) ] )
# g.db.commit() g.db.commit()
# flash("Hello " + request.form['username'] + ", you have successfully registered!") flash("Hello " + request.form['username'] + ", you have successfully registered!")
# session_login( request.form['username'] ) session_login( request.form['username'] )
# return redirect( "challenges" ) return redirect( "challenges" )
# return render( 'register.html', error = error ) return render( 'register.html', error = error )
# @app.route("/scoreboard") @app.route("/scoreboard")
# def scoreboard(): def scoreboard():
# cur = g.db.execute('select username, score from users order by score desc, last_submission asc') cur = g.db.execute('select username, score from users order by score desc, last_submission asc')
# response = cur.fetchall() response = cur.fetchall()
# users = [ { "username": row[0], "score": row[1] } for row in response] users = [ { "username": row[0], "score": row[1] } for row in response]
# return render("scoreboard.html", users = users ) return render("scoreboard.html", users = users )
# @app.route("/logout") @app.route("/logout")
# def logout(): def logout():
# session_logout() session_logout()
# return redirect("about") return redirect("about")
# @app.route("/") @app.route("/")
# @app.route("/about") @app.route("/about")
# def about(): return render("about.html", app_about=configuration['app_about']) def about(): return render("about.html", app_about=configuration['app_about'])
# @app.route("/challenges") @app.route("/challenges")
# def challenges_page(): def challenges_page():
# if not ( session['logged_in'] ): if not ( session['logged_in'] ):
# return render("login.html", error = "You must log in to be able to see the challenges!") return render("login.html", error = "You must log in to be able to see the challenges!")
# try: try:
# cur = g.db.execute('select uuid from users where username =?', cur = g.db.execute('select uuid from users where username =?',
# [ session['username'],] ) [ session['username'],] )
# uuid = cur.fetchone()[0] uuid = cur.fetchone()[0]
# except Exception as e: except Exception as e:
# print error(e.message) print error(e.message)
# uuid = '' uuid = ''
# return render("challenges.html", challenges = configuration['services'], url=request.url_root, session_value = uuid ) return render("challenges.html", challenges = configuration['services'], url=request.url_root, session_value = uuid )
# @app.route("/check_answer", methods=["GET", "POST"]) @app.route("/check_answer", methods=["GET", "POST"])
# def check_answer(): def check_answer():
# global correct_answers global correct_answers
# if request.method == "POST": if request.method == "POST":
# if request.form['answer'] in session['solved_challenges']: if request.form['answer'] in session['solved_challenges']:
# return json.dumps({'correct': -1}); return json.dumps({'correct': -1});
# if ( request.form['answer'] in correct_answers.keys() ): if ( request.form['answer'] in correct_answers.keys() ):
# flag = request.form['answer'] flag = request.form['answer']
# new_score = int(session['score']) + correct_answers[flag] new_score = int(session['score']) + correct_answers[flag]
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')) where username = (?)", [ cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')) where username = (?)", [
# new_score, new_score,
# session['username'] session['username']
# ] ); ] );
# session['solved_challenges'].append( request.form['answer'] ) session['solved_challenges'].append( request.form['answer'] )
# session['score'] = new_score session['score'] = new_score
# g.db.commit(); g.db.commit();
# return json.dumps({'correct': 1, 'new_score': new_score}); return json.dumps({'correct': 1, 'new_score': new_score});
# else: else:
# return json.dumps({'correct': 0}); return json.dumps({'correct': 0});
# @app.route("/submit", methods=[ "POST" ]) @app.route("/submit", methods=[ "POST" ])
# def submit(): def submit():
# global correct_answers global correct_answers
# if request.method == "POST": if request.method == "POST":
# if ( request.form['flag'] in correct_answers.keys() ): if ( request.form['flag'] in correct_answers.keys() ):
# flag = request.form['flag'] flag = request.form['flag']
# cur = g.db.execute('select score, solved_challenges from users where uuid = (?)', cur = g.db.execute('select score, solved_challenges from users where uuid = (?)',
# [ request.form['uuid'], ]) [ request.form['uuid'], ])
# current_score, solved_challenges = cur.fetchone() current_score, solved_challenges = cur.fetchone()
# solved_challenges = solved_challenges.split() solved_challenges = solved_challenges.split()
# if ( flag in solved_challenges ): if ( flag in solved_challenges ):
# return 'You already submitted this flag!\n' return 'You already submitted this flag!\n'
# print solved_challenges print solved_challenges
# new_score = current_score + correct_answers[flag] new_score = current_score + correct_answers[flag]
# solved_challenges.append( flag + " " ) solved_challenges.append( flag + " " )
# cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')), solved_challenges = (?) where uuid = (?)", [ cur = g.db.execute("update users set score = (?), last_submission = (SELECT strftime('%s')), solved_challenges = (?) where uuid = (?)", [
# new_score, new_score,
# ' '.join(solved_challenges), ' '.join(solved_challenges),
# request.form['uuid'] request.form['uuid']
# ] ); ] );
# # session['solved_challenges'].append( request.form['flag'] ) # session['solved_challenges'].append( request.form['flag'] )
# session['score'] = new_score session['score'] = new_score
# g.db.commit(); g.db.commit();
# # return json.dumps({'correct': 1, 'new_score': new_score}); # return json.dumps({'correct': 1, 'new_score': new_score});
# return 'Correct!\n'; return 'Correct!\n';
# else: else:
# # return json.dumps({'correct': 0}); # return json.dumps({'correct': 0});
# return 'Incorrect!\n'; return 'Incorrect!\n';
def session_login( username ): def session_login( username ):
flash("You were successfully logged in!") flash("You were successfully logged in!")
# cur = g.db.execute('select solved_challenges, score from users where username = (?)', cur = g.db.execute('select solved_challenges, score from users where username = (?)',
# [username]) [username])
# solved_challenges, score = cur.fetchone() solved_challenges, score = cur.fetchone()
session['logged_in'] = True session['logged_in'] = True
# session['username'] = username session['username'] = username
# session['score'] = score session['score'] = score
# session['solved_challenges'] = [] session['solved_challenges'] = []
def session_logout(): def session_logout():
flash("You have been successfully logged out.") flash("You have been successfully logged out.")
session['logged_in'] = False session['logged_in'] = False
# session.pop('username') session.pop('username')
# session.pop('score') session.pop('score')
if ( __name__ == "__main__" ): if ( __name__ == "__main__" ):
context = (CERTIFICATE, PRIVATE_KEY) context = (CERTIFICATE, PRIVATE_KEY)

View File

@ -8,7 +8,6 @@
# Optional variables: this should be modified by the commandline arguments # Optional variables: this should be modified by the commandline arguments
DATABASE="" DATABASE=""
CONFIGURATION=""
# Internal variables; do not edit. # Internal variables; do not edit.
DEPENDENCIES="python-pip sqlite3 python-flask python-passlib" DEPENDENCIES="python-pip sqlite3 python-flask python-passlib"
@ -150,12 +149,6 @@ if [ "$DATABASE" == "" ]; then
exit -1 exit -1
fi 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 # This makes it so every function has a "pre-declaration" of all the functions
main "$@" main "$@"

13
static/js/jquery-ui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

5
static/js/jquery.js vendored Normal file

File diff suppressed because one or more lines are too long

1
static/js/notify.js Normal file

File diff suppressed because one or more lines are too long

19
templates/base_page.html Normal file
View File

@ -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>

24
templates/login.html Normal file
View File

@ -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 %}

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title> Login -- USCGA BearShop</title> <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> </head>
<body> <body>