From 246ef0054052ca6152cc251f77128dfa677bccd9 Mon Sep 17 00:00:00 2001 From: forest Date: Sat, 9 May 2020 20:36:14 -0500 Subject: [PATCH] broken auth WIP --- README.md | 2 +- capsulflask/auth.py | 53 +++++++++++++++++++ capsulflask/db.py | 28 +++++----- capsulflask/model.py | 10 ++++ .../01_up_create_schemaversion.sql | 5 ++ .../02_down_accounts_vms_etc.sql | 9 ++++ .../02_up_accounts_vms_etc.sql | 28 ++++++++++ 7 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 capsulflask/auth.py create mode 100644 capsulflask/model.py create mode 100644 capsulflask/schema_migrations/01_up_create_schemaversion.sql create mode 100644 capsulflask/schema_migrations/02_down_accounts_vms_etc.sql create mode 100644 capsulflask/schema_migrations/02_up_accounts_vms_etc.sql diff --git a/README.md b/README.md index b9ea148..8614d12 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ source .venv/bin/activate pip install -r requirements.txt ``` -Run an instance of Postgres (I used docker for this, point is its listening on localhost:5432) +Run an instance of Postgres (I used docker for this, you can use whatever you want, point is its listening on localhost:5432) ``` docker run -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres diff --git a/capsulflask/auth.py b/capsulflask/auth.py new file mode 100644 index 0000000..30cfd8f --- /dev/null +++ b/capsulflask/auth.py @@ -0,0 +1,53 @@ +import functools + +from flask import Blueprint +from flask import g +from flask import redirect +from flask import url_for +from flask import session + +from capsulflask.db import get_model + +bp = Blueprint("auth", __name__, url_prefix="/auth") + +def account_required(view): + """View decorator that redirects anonymous users to the login page.""" + + @functools.wraps(view) + def wrapped_view(**kwargs): + if session.get("account") is None: + return redirect(url_for("auth.login")) + + return view(**kwargs) + + return wrapped_view + + +@bp.route("/register", methods=("GET", "POST")) +def register(): + + if request.method == "POST": + email = request.form["email"] + model = get_model() + error = None + + if not email: + error = "Email is required." + elif ( + model. + ): + error = f"User {username} is already registered." + + if error is None: + # the name is available, store it in the database and go to + # the login page + db.execute( + "INSERT INTO user (username, password) VALUES (?, ?)", + (username, generate_password_hash(password)), + ) + db.commit() + return redirect(url_for("auth.login")) + + flash(error) + + return render_template("auth/register.html") diff --git a/capsulflask/db.py b/capsulflask/db.py index a987b38..f877fb3 100644 --- a/capsulflask/db.py +++ b/capsulflask/db.py @@ -8,6 +8,7 @@ from psycopg2 import pool from flask import current_app from flask import g +from capsulflask.model import Model def init_app(app): databaseUrl = urlparse(app.config['DATABASE_URL']) @@ -30,14 +31,14 @@ def init_app(app): with open(join(schemaMigrationsPath, filename), 'rb') as file: schemaMigrations[key] = file.read().decode("utf8") - db = app.config['PSYCOPG2_CONNECTION_POOL'].getconn() + connection = app.config['PSYCOPG2_CONNECTION_POOL'].getconn() hasSchemaVersionTable = False actionWasTaken = False schemaVersion = 0 desiredSchemaVersion = 2 - cursor = db.cursor() + cursor = connection.cursor() cursor.execute(""" SELECT table_name, table_schema FROM information_schema.tables WHERE table_schema = '{}' @@ -52,7 +53,7 @@ def init_app(app): print("no table named schemaversion found in the {} schema. running migration 01_up".format(app.config['DATABASE_SCHEMA'])) try: cursor.execute(schemaMigrations["01_up"]) - db.commit() + connection.commit() except: print("unable to create the schemaversion table because: {}".format(my_exec_info_message(sys.exc_info()))) exit(1) @@ -74,7 +75,7 @@ def init_app(app): )) try: cursor.execute(schemaMigrations[migrationKey]) - db.commit() + connection.commit() except KeyError: print("missing schema migration script: {}_xyz.sql".format(migrationKey)) exit(1) @@ -97,7 +98,7 @@ def init_app(app): cursor.close() - app.config['PSYCOPG2_CONNECTION_POOL'].putconn(db) + app.config['PSYCOPG2_CONNECTION_POOL'].putconn(connection) print("{} current schemaVersion: \"{}\"".format( ("schema migration completed." if actionWasTaken else "schema is already up to date. "), schemaVersion @@ -106,17 +107,20 @@ def init_app(app): app.teardown_appcontext(close_db) -def get_db(): - if 'db' not in g: - g.db = current_app.config['PSYCOPG2_CONNECTION_POOL'].getconn() - return g.db +def get_model(): + if 'model' not in g: + connection = current_app.config['PSYCOPG2_CONNECTION_POOL'].getconn() + cursor = connection.cursor() + g.model = Model(connection, cursor) + return g.model def close_db(e=None): - db = g.pop("db", None) + model = g.pop("model", None) - if db is not None: - current_app.config['PSYCOPG2_CONNECTION_POOL'].putconn(db) + if model is not None: + model.cursor.close() + current_app.config['PSYCOPG2_CONNECTION_POOL'].putconn(model.connection) def my_exec_info_message(exec_info): return "{}: {}".format(".".join([exec_info[0].__module__, exec_info[0].__name__]), exec_info[1]) \ No newline at end of file diff --git a/capsulflask/model.py b/capsulflask/model.py new file mode 100644 index 0000000..af66f5f --- /dev/null +++ b/capsulflask/model.py @@ -0,0 +1,10 @@ + + +class Model: + def __init__(self, connection, cursor): + self.connection = connection + self.cursor = cursor + + def emailExists(self, email): + self.cursor.execute("SELECT * FROM accounts WHERE email = %(email)s", {"email": email}) + return len(self.cursor.fetchall()) > 0 \ No newline at end of file diff --git a/capsulflask/schema_migrations/01_up_create_schemaversion.sql b/capsulflask/schema_migrations/01_up_create_schemaversion.sql new file mode 100644 index 0000000..7251a3c --- /dev/null +++ b/capsulflask/schema_migrations/01_up_create_schemaversion.sql @@ -0,0 +1,5 @@ +CREATE TABLE schemaversion ( + version INT PRIMARY KEY NOT NULL +); + +INSERT INTO schemaversion(version) VALUES (1); \ No newline at end of file diff --git a/capsulflask/schema_migrations/02_down_accounts_vms_etc.sql b/capsulflask/schema_migrations/02_down_accounts_vms_etc.sql new file mode 100644 index 0000000..f501143 --- /dev/null +++ b/capsulflask/schema_migrations/02_down_accounts_vms_etc.sql @@ -0,0 +1,9 @@ +DROP TABLE payments; + +DROP TABLE logintokens; + +DROP TABLE vms; + +DROP TABLE accounts; + +UPDATE schemaversion SET version = 1; \ No newline at end of file diff --git a/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql b/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql new file mode 100644 index 0000000..d3da2bf --- /dev/null +++ b/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql @@ -0,0 +1,28 @@ + + +CREATE TABLE accounts ( + email TEXT PRIMARY KEY NOT NULL, +); + +CREATE TABLE vms ( + id TEXT PRIMARY KEY NOT NULL, + email TEXT REFERENCES accounts(email) ON DELETE RESTRICT, + created TIMESTAMP NOT NULL, + deleted TIMESTAMP NOT NULL, +); + +CREATE TABLE payments ( + email TEXT REFERENCES accounts(email) ON DELETE RESTRICT, + created TIMESTAMP NOT NULL, + dollars INTEGER NOT NULL, + PRIMARY KEY (email, created) +); + +CREATE TABLE logintokens ( + email TEXT REFERENCES accounts(email) ON DELETE RESTRICT, + created TIMESTAMP NOT NULL, + token TEXT NOT NULL, + PRIMARY KEY (email, created) +); + +UPDATE schemaversion SET version = 2; \ No newline at end of file