From 273248b95ead30e565a2ce62131f42f919c410a8 Mon Sep 17 00:00:00 2001
From: Shirkanesi <shirkanesi@shirkanesi.com>
Date: Sat, 19 Aug 2023 00:43:12 +0200
Subject: [PATCH] Initial work on auth-tokens

---
 jon/__init__.py         | 14 ++++++++++++++
 jon/auth.py             | 37 +++++++++++++++++++++++++++++++++++++
 jon/inventory.py        |  7 +++++++
 jon/templates/base.html |  1 +
 requirements.txt        |  1 +
 5 files changed, 60 insertions(+)
 create mode 100644 jon/auth.py

diff --git a/jon/__init__.py b/jon/__init__.py
index 7766f92..d3ef827 100644
--- a/jon/__init__.py
+++ b/jon/__init__.py
@@ -2,8 +2,10 @@ import inspect
 import json
 
 from flask import Flask, render_template
+from flask_login import LoginManager
 
 from . import (
+    auth,
     db,
     entry,
     inventory,
@@ -21,6 +23,15 @@ def create_app():
 
     db.init_app(app)
 
+    login_manager = LoginManager()
+    login_manager.login_view = 'auth.login'
+    login_manager.init_app(app)
+
+    @login_manager.user_loader
+    def load_user(user_id):
+        # since the user_id is just the primary key of our user table, use it in the query for the user
+        return auth.User()
+
     @app.context_processor
     def utility_processor():
         return dict(inspect.getmembers(template_utils, inspect.isfunction))
@@ -28,8 +39,11 @@ def create_app():
     app.register_blueprint(location.bp)
     app.register_blueprint(inventory.bp)
     app.register_blueprint(entry.bp)
+    app.register_blueprint(auth.auth)
     @app.route("/")
     def index():
         return render_template("index.html")
 
+    print("Jon started. Token: %s" % auth.ACCESS_TOKEN)
+
     return app
diff --git a/jon/auth.py b/jon/auth.py
new file mode 100644
index 0000000..b5eeb75
--- /dev/null
+++ b/jon/auth.py
@@ -0,0 +1,37 @@
+from flask import Blueprint, request, redirect
+from flask_login import login_user, UserMixin, login_required, logout_user
+from . import db
+import random
+import string
+
+auth = Blueprint('auth', __name__)
+
+ACCESS_TOKEN = ''.join(random.choice(string.ascii_lowercase) for i in range(64))
+
+class User(UserMixin):
+    id: int = 0
+
+@auth.route('/login')
+def login():
+    token = request.args.get('token')
+    next: str = request.args.get('next') or "/"
+    if token is None:
+        # TODO: make template
+        return """
+                No token provided!
+                <form action="" method="get">
+                    <input type="password" name="token" placeholder="Token" />
+                    <input type="hidden" hidden name="next" value="{next}" />
+                    <input type="submit" value="login" />
+                </form>
+                """.format(next=next)
+    if token == ACCESS_TOKEN:
+        login_user(User(), remember=True)
+        return redirect(next)
+    else:
+        return "Invalid token!"
+
+@auth.route('/logout')
+def logout():
+    logout_user()
+    return redirect("/")
diff --git a/jon/inventory.py b/jon/inventory.py
index 43aafad..c1422a3 100644
--- a/jon/inventory.py
+++ b/jon/inventory.py
@@ -1,4 +1,5 @@
 from flask import Blueprint, redirect, render_template, request, session
+from flask_login import login_required
 
 from . import db
 
@@ -7,6 +8,7 @@ bp = Blueprint("inventory", __name__, url_prefix="/inventory")
 
 
 @bp.get("/")
+@login_required
 def index():
     location = session.get("location", None)
     items = db.run_query("get_inventory_overview.sql", {
@@ -19,6 +21,7 @@ def index():
 
 
 @bp.get("/report")
+@login_required
 def read_report():
     location = session.get("location", None)
     items = db.run_query("get_inventory_report.sql", {
@@ -31,6 +34,7 @@ def read_report():
 
 
 @bp.get("/item/<item_id>")
+@login_required
 def read_item(item_id: int):
     item = db.run_query("get_item_by_id.sql", {
         "item_id": item_id
@@ -53,6 +57,7 @@ def read_item(item_id: int):
 
 
 @bp.post("/item/<item_id>/deactivate")
+@login_required
 def deactivate_item(item_id: int):
     item = db.run_query("get_item_by_id.sql", {
         "item_id": item_id
@@ -70,6 +75,7 @@ def deactivate_item(item_id: int):
 
 
 @bp.post("/correction")
+@login_required
 def create_correction():
     try:
         item_id = int(request.form.get("item_id"))
@@ -95,6 +101,7 @@ def create_correction():
 
 
 @bp.post("/transfer")
+@login_required
 def transfer_items():
     try:
         from_item_id = int(request.form.get("from_item_id"))
diff --git a/jon/templates/base.html b/jon/templates/base.html
index f71f7e1..4398641 100644
--- a/jon/templates/base.html
+++ b/jon/templates/base.html
@@ -88,6 +88,7 @@
             {% endif %}
             </a>
           </li>
+          <li {{ "class=current-page" if request.path.startswith("/logout") else "" }}><a href="/logout">Logout</a></li>
         </ul>
       </nav>
 
diff --git a/requirements.txt b/requirements.txt
index 555baae..c4968a8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,7 @@
 blinker==1.6.2
 click==8.1.3
 Flask==2.3.2
+flask-login
 itsdangerous==2.1.2
 Jinja2==3.1.2
 MarkupSafe==2.1.2