Added templates, javascript (jquery), and a cleaning script
parent
10ae797fa5
commit
5faabce182
12
README.md
12
README.md
|
@ -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/
|
||||||
|
@ -40,4 +47,5 @@ File & Directory Information
|
||||||
[SQL]: https://en.wikipedia.org/wiki/SQL
|
[SQL]: https://en.wikipedia.org/wiki/SQL
|
||||||
[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
|
|
@ -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
|
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)
|
||||||
|
|
7
setup.sh
7
setup.sh
|
@ -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 "$@"
|
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>
|
<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>
|
||||||
|
|
Loading…
Reference in New Issue