diff --git a/app.py b/app.py deleted file mode 100644 index 8222776..0000000 --- a/app.py +++ /dev/null @@ -1,14 +0,0 @@ -from flask import * -from random import randint as rint - -app = Flask(__name__) - - -@app.route('/') -def home(): - version = rint(0, 300000000) - return render_template('index.html', version=str(version)) - - -if __name__ == "__main__": - app.run() diff --git a/requirements.txt b/requirements.txt index 41959c7..0e6243d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,15 @@ click==7.1.2 Flask==1.1.2 +Flask-SocketIO==4.3.1 +Flask-WTF==0.14.3 gunicorn==20.0.4 itsdangerous==1.1.0 Jinja2==2.11.2 MarkupSafe==1.1.1 +pycryptodome==3.9.8 +python-dotenv==0.14.0 +python-engineio==3.13.2 +python-socketio==4.6.0 +six==1.15.0 Werkzeug==1.0.1 +WTForms==2.3.3 diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..3906df4 --- /dev/null +++ b/src/app.py @@ -0,0 +1,94 @@ +from flask import * +from random import randint as rint +from src.config import Config +from src.host import HostForm +from src.sec import gencode, dohash +from logging.config import dictConfig +import logging +from flask_socketio import SocketIO +import json + +dictConfig({ + 'version': 1, + 'formatters': {'default': { + 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', + }}, + 'handlers': {'wsgi': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://flask.logging.wsgi_errors_stream', + 'formatter': 'default' + }}, + 'root': { + 'level': 'INFO', + 'handlers': ['wsgi'] + } +}) + +app = Flask(__name__) +app.logger.info("Flask app loaded at " + __name__) +app.config.from_object(Config) + +app.logger.setLevel(logging.DEBUG) + +version = rint(0, 300000000) +games = {} + + +@app.route('/') +def home(): + return render_template('index.html', version=str(version)) + + +@app.route("/host", methods=["GET", "POST"]) +def host(): + form = HostForm() + if form.validate_on_submit(): + hostcode = gencode(64) + hash = dohash(hostcode) + resp = redirect(url_for("play", hash=hash)) + resp.set_cookie("_gid", str(hostcode), httponly=True, secure=True) + with open("src/templates/games.json", "r") as f: + tmp = json.load(f) + games[hash] = tmp + games[hash]["hostcode"] = hostcode + games[hash]["tossup"] = form.tossup.data + games[hash]["bonus"] = form.bonus.data + games[hash]["power"] = form.power.data + games[hash]["negs"] = form.negs.data + games[hash]["teams"] = form.teams.data + app.logger.debug("Game host at %s", hostcode) + app.logger.info("Game created at %s", hash) + return resp + default = [10, 20, 15, 5] + return render_template('host.html', title="Host Game", version=str(version), form=form, default=default) + + +@app.route("/play/") +def play(hash): + if hash in games.keys(): + return render_template('play.html', version=str(version)) + else: + abort(404) + + +@app.route("/join") +def join(): + return "In progress!" + + +@app.errorhandler(404) +def page_not_found(e): + return render_template('404.html'), 404 + + +socketio = SocketIO(app) + + +@socketio.on('json') +def handle_json(json): + print('received message: ' + str(json)) + + +if __name__ == "__main__": + socketio.run(app) +# app.run(host="127.0.0.1", port=25565) diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..498e485 --- /dev/null +++ b/src/config.py @@ -0,0 +1,8 @@ +from dotenv import load_dotenv +import os + +load_dotenv() + + +class Config(object): + SECRET_KEY = os.getenv('SECRET_KEY') or "debug-secret-key-for-testing-only" diff --git a/src/host.py b/src/host.py new file mode 100644 index 0000000..d0ebf4b --- /dev/null +++ b/src/host.py @@ -0,0 +1,10 @@ +from flask_wtf import FlaskForm +from wtforms import IntegerField, SubmitField, BooleanField +from wtforms.validators import DataRequired +class HostForm(FlaskForm): + tossup = IntegerField('Tossup Points', validators=[DataRequired()]) + bonus = IntegerField('Bonus Points', validators=[DataRequired()]) + power = IntegerField('Power Points', validators=[DataRequired()]) + negs = IntegerField('Neg Points [Positive]', validators=[DataRequired()]) + teams = BooleanField('Teams? ') + create = SubmitField('Create Room') \ No newline at end of file diff --git a/src/join.py b/src/join.py new file mode 100644 index 0000000..ba0f6b4 --- /dev/null +++ b/src/join.py @@ -0,0 +1,6 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, BooleanField +from wtforms.validators import DataRequired +class JoinForm(FlaskForm): + roomcode = StringField('Room Code', validators=[DataRequired()]) + create = SubmitField('Join Room') \ No newline at end of file diff --git a/src/sec.py b/src/sec.py new file mode 100644 index 0000000..1bfb7c5 --- /dev/null +++ b/src/sec.py @@ -0,0 +1,34 @@ +from Crypto.Hash import SHA256, SHA3_256, SHAKE128 +import secrets +from string import ascii_letters, digits +from binascii import hexlify + + +def gencode(n): + return ''.join([secrets.choice(ascii_letters + digits) for i in range(n)]) + + +def sha256(val): + h = SHA256.new() + h.update(bytes(str(val).encode('utf-8'))) + return h.digest() + + +def sha3256(val): + ho = SHA3_256.new() + ho.update(bytes(str(val).encode('utf-8'))) + return ho.digest() + + +def hexdigest(val): + return hexlify(val).decode('utf-8') + + +def shake(val, n): + xh = SHAKE128.new() + xh.update(val) + return xh.read(n) + + +def dohash(val): + return hexdigest(shake(sha3256(sha256(val)), 7)) diff --git a/static/Abberancy-Regular.svg b/src/static/Abberancy-Regular.svg similarity index 100% rename from static/Abberancy-Regular.svg rename to src/static/Abberancy-Regular.svg diff --git a/static/Abberancy-Regular.ttf b/src/static/Abberancy-Regular.ttf similarity index 100% rename from static/Abberancy-Regular.ttf rename to src/static/Abberancy-Regular.ttf diff --git a/static/abberancy.eot b/src/static/abberancy.eot similarity index 100% rename from static/abberancy.eot rename to src/static/abberancy.eot diff --git a/src/static/favicon.ico b/src/static/favicon.ico new file mode 100644 index 0000000..d5c0b9d Binary files /dev/null and b/src/static/favicon.ico differ diff --git a/src/static/game.js b/src/static/game.js new file mode 100644 index 0000000..9f392de --- /dev/null +++ b/src/static/game.js @@ -0,0 +1,7 @@ +var socket = io(); +test = function() { + console.log("h"); + socket.emit('json', {data: 'I\'m connected!'}); +} + +// div id = game (that's where the game goes) \ No newline at end of file diff --git a/static/index.css b/src/static/index.css similarity index 70% rename from static/index.css rename to src/static/index.css index eb969c9..7570866 100644 --- a/static/index.css +++ b/src/static/index.css @@ -20,7 +20,13 @@ body { font-size: 3.3rem; } -.button { +.subttl { + text-align: center; + font-family: 'Abberancy-Regular'; + font-size: 2rem; +} + +.center { align-items: center; justify-content: center; } @@ -63,6 +69,30 @@ body { color: white; } +.back { + background: -webkit-gradient(to right,#a2ccb6 0%,#fceeb5 50%,#ee786e 100%); + background: linear-gradient(to right,#a2ccb6 0%,#fceeb5 50%,#ee786e 100%); + border-top: 12px; + padding-right: 12px; + padding-left: 12px; + padding-bottom: 6px; + padding-top: 6px; + border-radius: 3.75rem; + border-style: none; + box-shadow: 0 .5rem 1rem rgba(0,0,0,.15); + width: 15rem; + letter-spacing: 0.13rem; + background-size: 300%; + text-decoration: none; + color: white; + font: 0.5em Raleway, sans-serif; +} +.top { + margin-top: 17px; + margin-left: 5px; +} + + @font-face { font-family: 'Abberancy-Regular'; src: url('Abberancy-Regular.svg#Abberancy-Regular') format('svg'), diff --git a/src/templates/404.html b/src/templates/404.html new file mode 100644 index 0000000..0f9f9e0 --- /dev/null +++ b/src/templates/404.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% block content %} +
+

404 Error

+
+
+
Page not found
+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/base.html b/src/templates/base.html new file mode 100644 index 0000000..ba80b74 --- /dev/null +++ b/src/templates/base.html @@ -0,0 +1,20 @@ + + + {% if title %} + + + + + {{ title }} - Buzzer! + + {% else %} + + Buzzer! + + + + {% endif %} + + {% block content %}{% endblock %} + + \ No newline at end of file diff --git a/src/templates/games.json b/src/templates/games.json new file mode 100644 index 0000000..a9f90e3 --- /dev/null +++ b/src/templates/games.json @@ -0,0 +1,8 @@ +{ + "hostcode": "", + "tossup": 10, + "bonus": 20, + "power": 15, + "negs": 5, + "teams": false +} \ No newline at end of file diff --git a/src/templates/host.html b/src/templates/host.html new file mode 100644 index 0000000..3575e0c --- /dev/null +++ b/src/templates/host.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} + +{% block content %} +
+ Back +
+
+

Host Game

+
+
+ {{ form.csrf_token }} + {{ form.hidden_tag() }} +

+ {{ form.tossup.label }}
+ {{ form.tossup(size=32, value=default[0]) }}
+ {% for error in form.tossup.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.bonus.label }}
+ {{ form.bonus(size=32, value=default[1]) }}
+ {% for error in form.bonus.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.power.label }}
+ {{ form.power(size=32, value=default[2]) }}
+ {% for error in form.power.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.negs.label }}
+ {{ form.negs(size=32, value=default[3]) }}
+ {% for error in form.negs.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.teams() }} {{ form.teams.label }}
+ {% for error in form.negs.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.create() }} +
+

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/index.html b/src/templates/index.html new file mode 100644 index 0000000..f6fc548 --- /dev/null +++ b/src/templates/index.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block content %} +
+

Buzzer!

+
+
+
+ Host Game +


+ Join Game +
+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/inprogress.html b/src/templates/inprogress.html new file mode 100644 index 0000000..cead3bf --- /dev/null +++ b/src/templates/inprogress.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block content %} +
+

In Progress!

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/join.html b/src/templates/join.html new file mode 100644 index 0000000..b04a1d4 --- /dev/null +++ b/src/templates/join.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} + +{% block content %} +
+ Back +
+
+

Host Game

+
+
+ {{ form.csrf_token }} + {{ form.hidden_tag() }} +

+ {{ form.tossup.label }}
+ {{ form.tossup(size=32, value=default[0]) }}
+ {% for error in form.tossup.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.bonus.label }}
+ {{ form.bonus(size=32, value=default[1]) }}
+ {% for error in form.bonus.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.power.label }}
+ {{ form.power(size=32, value=default[2]) }}
+ {% for error in form.power.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.negs.label }}
+ {{ form.negs(size=32, value=default[3]) }}
+ {% for error in form.negs.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.teams() }} {{ form.teams.label }}
+ {% for error in form.negs.errors %} + [{{ error }}]
+ {% endfor %} +
+ {{ form.create() }} +
+

+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/play.html b/src/templates/play.html new file mode 100644 index 0000000..b6290ca --- /dev/null +++ b/src/templates/play.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{% block content %} + + +
+ +
+{% endblock %} diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index d59bd2c..0000000 --- a/templates/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - {% if title %} - - {{ title }} - Buzzer! - - {% else %} - Buzzer! - {% endif %} - -
-

Buzzer!

-
-
-
- Host Game -


- Join Game -
-
- - \ No newline at end of file diff --git a/templates/navbar.html b/templates/navbar.html deleted file mode 100644 index 7eebd38..0000000 --- a/templates/navbar.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - {% block content %}{% endblock %} - - \ No newline at end of file