from flask import Flask, render_template, request, g, jsonify
import sqlite3
import hashcash
import freenode
hash_difficulty = 4
hash_expiry = 7 # Days
def get_db():
db = getattr(g, "database", None)
if db is None:
db = g.database = sqlite3.connect("database.db", detect_types=sqlite3.PARSE_DECLTYPES)
db.row_factory = sqlite3.Row
db.cursor().execute("PRAGMA foreign_keys = ON;")
db.commit()
return db
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/register", methods=["POST"])
def register():
try:
token = request.form["token"]
username = request.form["username"]
password = request.form["password"]
fingerprint = request.form["fingerprint"]
except KeyError as e:
return jsonify({"status": "failure", "reason": "incomplete registration details", "token_reusable": True})
database = get_db()
# Verify Token
# Failure?
# Return failed page.
# Insert Token
# Failure?
# Return failed page.
# Register user
# Success?
# Commit token
# Return success page
# Failure?
# Rollback Token
# Return failure page (with token for re-use)
try:
token_valid = hashcash.hashcash_check(token, "freenode.net", hash_difficulty, hash_expiry * 24 * 60 * 60)
except AssertionError as e:
return jsonify({"status": "failure", "reason": str(e), "token_reusable": False})
if not token_valid:
return jsonify({"status": "failure", "reason": "invalid token", "token_reusable": False})
cursor = database.cursor()
try:
cursor.execute("insert into tokens (token, entry_time) values (?, datetime('now'));", (token,))
except sqlite3.IntegrityError:
database.rollback()
return jsonify({"status": "failure", "reason": "token has already been used", "token_reusable": False})
except Exception as e:
database.rollback()
return jsonify({"status": "failure", "reason": str(e)})
try:
freenode.register_user(username, password, certfp=fingerprint)
database.commit()
except NotImplementedError as e: # registration_error
database.rollback()
# Raise error page with appropriate info (username in use, invalid chars, etc)
return jsonify({"status": "failure", "reason": str(e), "token_reusable": True})
except Exception as e:
database.rollback()
# Raise error page with generic info (also token still valid)
return jsonify({"status": "failure", "reason": str(e), "token_reusable": True})
return jsonify({"status": "success", "username": username, "token_reusable": False})
def cleanup(): # Should run every day
database = get_db()
cursor = database.cursor()
cursor.execute("delete from tokens where entry_time < datetime('now', ?);", ("-"+hash_expiry+" days",))
database.commit()