next
This commit is contained in:
parent
ac07eab441
commit
06b86d706e
14
app.py
14
app.py
|
@ -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()
|
|
|
@ -1,7 +1,15 @@
|
||||||
click==7.1.2
|
click==7.1.2
|
||||||
Flask==1.1.2
|
Flask==1.1.2
|
||||||
|
Flask-SocketIO==4.3.1
|
||||||
|
Flask-WTF==0.14.3
|
||||||
gunicorn==20.0.4
|
gunicorn==20.0.4
|
||||||
itsdangerous==1.1.0
|
itsdangerous==1.1.0
|
||||||
Jinja2==2.11.2
|
Jinja2==2.11.2
|
||||||
MarkupSafe==1.1.1
|
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
|
Werkzeug==1.0.1
|
||||||
|
WTForms==2.3.3
|
||||||
|
|
94
src/app.py
Normal file
94
src/app.py
Normal file
|
@ -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/<hash>")
|
||||||
|
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)
|
8
src/config.py
Normal file
8
src/config.py
Normal file
|
@ -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"
|
10
src/host.py
Normal file
10
src/host.py
Normal file
|
@ -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')
|
6
src/join.py
Normal file
6
src/join.py
Normal file
|
@ -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')
|
34
src/sec.py
Normal file
34
src/sec.py
Normal file
|
@ -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))
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
BIN
src/static/favicon.ico
Normal file
BIN
src/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 318 B |
7
src/static/game.js
Normal file
7
src/static/game.js
Normal file
|
@ -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)
|
|
@ -20,7 +20,13 @@ body {
|
||||||
font-size: 3.3rem;
|
font-size: 3.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.subttl {
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'Abberancy-Regular';
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +69,30 @@ body {
|
||||||
color: white;
|
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-face {
|
||||||
font-family: 'Abberancy-Regular';
|
font-family: 'Abberancy-Regular';
|
||||||
src: url('Abberancy-Regular.svg#Abberancy-Regular') format('svg'),
|
src: url('Abberancy-Regular.svg#Abberancy-Regular') format('svg'),
|
9
src/templates/404.html
Normal file
9
src/templates/404.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="title">
|
||||||
|
<h1> 404 Error </h1>
|
||||||
|
</div>
|
||||||
|
<div class="title">
|
||||||
|
<h6>Page not found</h6>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
20
src/templates/base.html
Normal file
20
src/templates/base.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
{% if title %}
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
|
||||||
|
<link rel="stylesheet" href="/static/index.css?version={{ version }}">
|
||||||
|
<title>{{ title }} - Buzzer! </title>
|
||||||
|
</head>
|
||||||
|
{% else %}
|
||||||
|
<head>
|
||||||
|
<title> Buzzer! </title>
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
|
||||||
|
<link rel="stylesheet" href="/static/index.css?version={{ version }}">
|
||||||
|
</head>
|
||||||
|
{% endif %}
|
||||||
|
<body class="wrap">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
8
src/templates/games.json
Normal file
8
src/templates/games.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"hostcode": "",
|
||||||
|
"tossup": 10,
|
||||||
|
"bonus": 20,
|
||||||
|
"power": 15,
|
||||||
|
"negs": 5,
|
||||||
|
"teams": false
|
||||||
|
}
|
47
src/templates/host.html
Normal file
47
src/templates/host.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="button top">
|
||||||
|
<a href="{{ url_for('home') }}">Back</a>
|
||||||
|
</div>
|
||||||
|
<div class="subttl">
|
||||||
|
<h1> Host Game </h1>
|
||||||
|
</div>
|
||||||
|
<form action="" method="post" novalidate>
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
<p>
|
||||||
|
{{ form.tossup.label }}<br>
|
||||||
|
{{ form.tossup(size=32, value=default[0]) }}<br>
|
||||||
|
{% for error in form.tossup.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.bonus.label }}<br>
|
||||||
|
{{ form.bonus(size=32, value=default[1]) }}<br>
|
||||||
|
{% for error in form.bonus.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.power.label }}<br>
|
||||||
|
{{ form.power(size=32, value=default[2]) }}<br>
|
||||||
|
{% for error in form.power.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.negs.label }}<br>
|
||||||
|
{{ form.negs(size=32, value=default[3]) }}<br>
|
||||||
|
{% for error in form.negs.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.teams() }} {{ form.teams.label }}<br>
|
||||||
|
{% for error in form.negs.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.create() }}
|
||||||
|
<br>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
14
src/templates/index.html
Normal file
14
src/templates/index.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="title">
|
||||||
|
<h1> Buzzer! </h1>
|
||||||
|
</div>
|
||||||
|
<div class="button">
|
||||||
|
<center>
|
||||||
|
<a href="{{ url_for('host') }}">Host Game</a>
|
||||||
|
<br><br><br>
|
||||||
|
<a href="{{ url_for('join') }}">Join Game</a>
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
7
src/templates/inprogress.html
Normal file
7
src/templates/inprogress.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="title">
|
||||||
|
<h1> In Progress! </h1>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
47
src/templates/join.html
Normal file
47
src/templates/join.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="button top">
|
||||||
|
<a href="{{ url_for('home') }}">Back</a>
|
||||||
|
</div>
|
||||||
|
<div class="subttl">
|
||||||
|
<h1> Host Game </h1>
|
||||||
|
</div>
|
||||||
|
<form action="" method="post" novalidate>
|
||||||
|
{{ form.csrf_token }}
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
<p>
|
||||||
|
{{ form.tossup.label }}<br>
|
||||||
|
{{ form.tossup(size=32, value=default[0]) }}<br>
|
||||||
|
{% for error in form.tossup.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.bonus.label }}<br>
|
||||||
|
{{ form.bonus(size=32, value=default[1]) }}<br>
|
||||||
|
{% for error in form.bonus.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.power.label }}<br>
|
||||||
|
{{ form.power(size=32, value=default[2]) }}<br>
|
||||||
|
{% for error in form.power.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.negs.label }}<br>
|
||||||
|
{{ form.negs(size=32, value=default[3]) }}<br>
|
||||||
|
{% for error in form.negs.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.teams() }} {{ form.teams.label }}<br>
|
||||||
|
{% for error in form.negs.errors %}
|
||||||
|
<span style="color: red;">[{{ error }}]</span><br>
|
||||||
|
{% endfor %}
|
||||||
|
<br>
|
||||||
|
{{ form.create() }}
|
||||||
|
<br>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
9
src/templates/play.html
Normal file
9
src/templates/play.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
|
||||||
|
<script src="/static/game.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<div id="game">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,22 +0,0 @@
|
||||||
<html>
|
|
||||||
<link rel="stylesheet" href="static/index.css?version={{ version }}">
|
|
||||||
{% if title %}
|
|
||||||
<head>
|
|
||||||
<title>{{ title }} - Buzzer! </title>
|
|
||||||
</head>
|
|
||||||
{% else %}
|
|
||||||
<head><title> Buzzer! </title></head>
|
|
||||||
{% endif %}
|
|
||||||
<body class="wrap">
|
|
||||||
<div class="title">
|
|
||||||
<h1> Buzzer! </h1>
|
|
||||||
</div>
|
|
||||||
<div class="button">
|
|
||||||
<center>
|
|
||||||
<a href="#">Host Game</a>
|
|
||||||
<br><br><br>
|
|
||||||
<a href="#">Join Game</a>
|
|
||||||
</center>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Reference in New Issue
Block a user