|
|
|
@ -21,25 +21,27 @@ import random |
|
|
|
|
import string |
|
|
|
|
from datetime import datetime, timedelta |
|
|
|
|
|
|
|
|
|
VERSION = '1.0.0' |
|
|
|
|
PORT = os.environ.get('PORT', 8080) |
|
|
|
|
DEBUG = os.environ.get('DEBUG', False) |
|
|
|
|
SQLITE_FILENAME = os.environ.get('SQLITE_FILENAME','/data/db.sqlite') |
|
|
|
|
DATABASE_URL = os.environ.get('DATABASE_URL','sqlite:///' + SQLITE_FILENAME) |
|
|
|
|
ADMIN_PSK = os.environ.get('ADMIN_PSK','hunter2') |
|
|
|
|
VERSION = "1.0.0" |
|
|
|
|
PORT = os.environ.get("PORT", 8080) |
|
|
|
|
DEBUG = os.environ.get("DEBUG", False) |
|
|
|
|
SQLITE_FILENAME = os.environ.get("SQLITE_FILENAME", "/data/db.sqlite") |
|
|
|
|
DATABASE_URL = os.environ.get("DATABASE_URL", "sqlite:///" + SQLITE_FILENAME) |
|
|
|
|
ADMIN_PSK = os.environ.get("ADMIN_PSK", "hunter2") |
|
|
|
|
|
|
|
|
|
# sorry for global |
|
|
|
|
SQLBASE = declarative_base() |
|
|
|
|
|
|
|
|
|
# FIXME make this skip letters not in base58 |
|
|
|
|
def randomUpper(count): |
|
|
|
|
return ''.join(random.choice(string.ascii_uppercase) for _ in range(count)) |
|
|
|
|
return "".join(random.choice(string.ascii_uppercase) for _ in range(count)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# FIXME maybe make the IDs longer |
|
|
|
|
def genRandomTVID(): |
|
|
|
|
tvid = str(randomUpper(3) + "-" + randomUpper(3)) |
|
|
|
|
return tvid |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def serve(): |
|
|
|
|
app = bottle.Bottle() |
|
|
|
|
|
|
|
|
@ -51,40 +53,40 @@ def serve(): |
|
|
|
|
plugin = sqlalchemy.Plugin( |
|
|
|
|
engine, |
|
|
|
|
SQLBASE.metadata, |
|
|
|
|
keyword='db', |
|
|
|
|
keyword="db", |
|
|
|
|
create=True, |
|
|
|
|
commit=True, |
|
|
|
|
use_kwargs=False |
|
|
|
|
use_kwargs=False, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
app.install(plugin) |
|
|
|
|
|
|
|
|
|
# here we cookie them if they have no cookie, then redirect them to the |
|
|
|
|
# cookie'd value (whether preexisting or new). |
|
|
|
|
@app.get('/') |
|
|
|
|
@app.get("/") |
|
|
|
|
def indexpage(): |
|
|
|
|
c = request.get_cookie("displayid") |
|
|
|
|
if c: |
|
|
|
|
# redirect |
|
|
|
|
return redirect('/tv/' + c) |
|
|
|
|
return redirect("/tv/" + c) |
|
|
|
|
else: |
|
|
|
|
newid = genRandomTVID() |
|
|
|
|
response.set_cookie("displayid", newid) |
|
|
|
|
return redirect('/tv/' + newid) |
|
|
|
|
return redirect("/tv/" + newid) |
|
|
|
|
|
|
|
|
|
@app.get('/style.css') |
|
|
|
|
@app.get("/style.css") |
|
|
|
|
def stylesheet(): |
|
|
|
|
response.content_type = 'text/css' |
|
|
|
|
return template('style') |
|
|
|
|
response.content_type = "text/css" |
|
|
|
|
return template("style") |
|
|
|
|
|
|
|
|
|
# here we check to see if they have a redirect URL in the db. if they do |
|
|
|
|
# we send them there. if they don't, we display their ID really big, |
|
|
|
|
# reloading the page once per hour. |
|
|
|
|
@app.get('/tv/<displayid>') |
|
|
|
|
@app.get("/tv/<displayid>") |
|
|
|
|
def tvpage(db, displayid=None): |
|
|
|
|
# FIXME check for cookie, this is broken |
|
|
|
|
if displayid is None: |
|
|
|
|
return template('nocookie') |
|
|
|
|
return template("nocookie") |
|
|
|
|
|
|
|
|
|
# check db for tv id |
|
|
|
|
tv = db.query(TV).filter_by(displayid=displayid).first() |
|
|
|
@ -94,61 +96,60 @@ def serve(): |
|
|
|
|
if tv.target: |
|
|
|
|
return redirect(tv.target) |
|
|
|
|
else: |
|
|
|
|
return template('displayid', id=displayid, version=VERSION) |
|
|
|
|
return template("displayid", id=displayid, version=VERSION) |
|
|
|
|
else: |
|
|
|
|
# otherwise, just show their display ID bigly and keep them |
|
|
|
|
# bouncing periodically until some admin configures them |
|
|
|
|
# a target: |
|
|
|
|
# update lastseen here: |
|
|
|
|
newtv = TV(displayid=displayid,lastSeen=datetime.now()) |
|
|
|
|
newtv = TV(displayid=displayid, lastSeen=datetime.now()) |
|
|
|
|
db.add(newtv) |
|
|
|
|
return template('displayid', id=displayid, version=VERSION) |
|
|
|
|
return template("displayid", id=displayid, version=VERSION) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get('/admin/edit/<displayid>') |
|
|
|
|
@app.get("/admin/edit/<displayid>") |
|
|
|
|
def displayeditform(db, displayid=None): |
|
|
|
|
c = request.get_cookie("psk") |
|
|
|
|
if not c: |
|
|
|
|
return redirect('/login') |
|
|
|
|
return redirect("/login") |
|
|
|
|
if c != ADMIN_PSK: |
|
|
|
|
return redirect('/logout') |
|
|
|
|
return redirect("/logout") |
|
|
|
|
if not displayid: |
|
|
|
|
return redirect('/admin') |
|
|
|
|
return redirect("/admin") |
|
|
|
|
tv = db.query(TV).filter_by(displayid=displayid).first() |
|
|
|
|
if tv is None: |
|
|
|
|
return redirect('/admin') |
|
|
|
|
return template('displayeditform', tv=tv, version=VERSION) |
|
|
|
|
return redirect("/admin") |
|
|
|
|
return template("displayeditform", tv=tv, version=VERSION) |
|
|
|
|
|
|
|
|
|
@app.post('/admin/edit') |
|
|
|
|
@app.post("/admin/edit") |
|
|
|
|
def displayedithandler(db): |
|
|
|
|
# FIXME SECURITY csrf issue |
|
|
|
|
c = request.get_cookie("psk") |
|
|
|
|
if not c: |
|
|
|
|
return redirect('/login') |
|
|
|
|
return redirect("/login") |
|
|
|
|
if c != ADMIN_PSK: |
|
|
|
|
return redirect('/logout') |
|
|
|
|
displayid = request.forms.get('displayid') |
|
|
|
|
return redirect("/logout") |
|
|
|
|
displayid = request.forms.get("displayid") |
|
|
|
|
tv = db.query(TV).filter_by(displayid=displayid).first() |
|
|
|
|
if tv is None: |
|
|
|
|
return redirect('/admin') |
|
|
|
|
return redirect("/admin") |
|
|
|
|
# FIXME make sure this is a valid URL |
|
|
|
|
tv.target = request.forms.get('target') |
|
|
|
|
tv.memo = request.forms.get('formmemo') |
|
|
|
|
tv.target = request.forms.get("target") |
|
|
|
|
tv.memo = request.forms.get("formmemo") |
|
|
|
|
db.add(tv) |
|
|
|
|
db.commit() |
|
|
|
|
return redirect('/admin') |
|
|
|
|
return redirect("/admin") |
|
|
|
|
|
|
|
|
|
# here we display the administration list of TVs if logged in |
|
|
|
|
# if logged out then redirect to /login |
|
|
|
|
# FIXME make this use sessions instead of just storing PSK in a cookie |
|
|
|
|
# https://bottlepy.org/docs/dev/recipes.html |
|
|
|
|
@app.get('/admin') |
|
|
|
|
@app.get("/admin") |
|
|
|
|
def adminpage(db): |
|
|
|
|
c = request.get_cookie("psk") |
|
|
|
|
if not c: |
|
|
|
|
return redirect('/login') |
|
|
|
|
return redirect("/login") |
|
|
|
|
if c != ADMIN_PSK: |
|
|
|
|
return redirect('/logout') |
|
|
|
|
return redirect("/logout") |
|
|
|
|
|
|
|
|
|
# first, cleanup db of old entries: |
|
|
|
|
week_ago = datetime.now() - timedelta(days=7) |
|
|
|
@ -156,36 +157,33 @@ def serve(): |
|
|
|
|
db.commit() |
|
|
|
|
|
|
|
|
|
tvs = db.query(TV).order_by(TV.lastSeen.desc()) |
|
|
|
|
response.headers['Cache-Control'] = 'no-cache' |
|
|
|
|
return template('adminpanel', tvs=tvs, version=VERSION) |
|
|
|
|
|
|
|
|
|
response.headers["Cache-Control"] = "no-cache" |
|
|
|
|
return template("adminpanel", tvs=tvs, version=VERSION) |
|
|
|
|
|
|
|
|
|
# here we ask for a password: |
|
|
|
|
@app.get('/login') |
|
|
|
|
@app.get("/login") |
|
|
|
|
def loginform(): |
|
|
|
|
msg = request.GET.msg |
|
|
|
|
return template('loginform', version=VERSION, msg=msg) |
|
|
|
|
return template("loginform", version=VERSION, msg=msg) |
|
|
|
|
|
|
|
|
|
@app.post('/checklogin') |
|
|
|
|
@app.post("/checklogin") |
|
|
|
|
def checklogin(): |
|
|
|
|
attemptedPass = request.forms.get('password') |
|
|
|
|
attemptedPass = request.forms.get("password") |
|
|
|
|
if not attemptedPass: |
|
|
|
|
return redirect( |
|
|
|
|
'/login?msg=' + |
|
|
|
|
urllib.parse.quote_plus(u"Incorrect password.") |
|
|
|
|
"/login?msg=" + urllib.parse.quote_plus(u"Incorrect password.") |
|
|
|
|
) |
|
|
|
|
if attemptedPass != ADMIN_PSK: |
|
|
|
|
return redirect( |
|
|
|
|
'/login?msg=' + |
|
|
|
|
urllib.parse.quote_plus(u"Incorrect password.") |
|
|
|
|
"/login?msg=" + urllib.parse.quote_plus(u"Incorrect password.") |
|
|
|
|
) |
|
|
|
|
# password is right, cookie them: |
|
|
|
|
response.set_cookie("psk", attemptedPass) |
|
|
|
|
return redirect('/admin') |
|
|
|
|
return redirect("/admin") |
|
|
|
|
|
|
|
|
|
@app.get('/logout') |
|
|
|
|
@app.get("/logout") |
|
|
|
|
def logout(): |
|
|
|
|
response.set_cookie("psk", "") |
|
|
|
|
return redirect('/login') |
|
|
|
|
return redirect("/login") |
|
|
|
|
|
|
|
|
|
app.run(host='0.0.0.0', port=PORT, debug=DEBUG) |
|
|
|
|
app.run(host="0.0.0.0", port=PORT, debug=DEBUG) |
|
|
|
|