Prechádzať zdrojové kódy

Added DB and table creation. Started working on getting the functionality working.

Adam Day 2 rokov pred
rodič
commit
dac56d7661
9 zmenil súbory, kde vykonal 312 pridanie a 33 odobranie
  1. 1 0
      .gitignore
  2. 185 12
      app.py
  3. BIN
      requirements.txt
  4. 4 0
      settings.ini
  5. 8 0
      templates/admin.html
  6. 34 0
      templates/auth_layout.html
  7. 53 3
      templates/index.html
  8. 3 18
      templates/layout.html
  9. 24 0
      templates/login.html

+ 1 - 0
.gitignore

@@ -3,3 +3,4 @@
 /app.spec
 /build/
 /dist/
+/users.db

+ 185 - 12
app.py

@@ -1,16 +1,46 @@
 import datetime as datetime
+import configparser as configparser
+import os
+from urllib.parse import urlparse
+import webbrowser
 from emailtool.emailer import Emailer
-from flask import Flask, render_template, request, redirect, url_for
+from flask import Flask, render_template, request, redirect, url_for, jsonify, session
+from flask_httpauth import HTTPBasicAuth
 import configparser
 from gevent.pywsgi import WSGIServer
 import socket
 import logging
+from peewee import Model, CharField, TextField, DateTimeField, SqliteDatabase, BooleanField
+import hashlib
+
+db_name = 'users.db'
+db = SqliteDatabase(db_name)
+
+
+class User(Model):
+    username = CharField()
+    password = CharField()
+    logged_in = BooleanField(default=False)
+
+    class Meta:
+        database = db
+
+
+class IlsUser(Model):
+    username = CharField()
+    email = CharField()
+    reset_datetime = DateTimeField(default=datetime.datetime.now)
+
+    class Meta:
+        database = db
+
 
 config = configparser.ConfigParser()
 config.read('settings.ini')
 application_settings = config['application']
 smtp_settings = config['smtp']
 http_settings = config['http']
+domain_settings = config['domain']
 
 log = logging.getLogger('werkzeug')
 log.setLevel(logging.INFO)
@@ -34,19 +64,12 @@ def send_email(to, subject, body):
     emailer.send_email(to, subject, body)
 
 
-app = Flask(__name__)
-
-
-# Create a route for the home page
-@app.route('/')
-def index():
-    # send_email('aday@twinfallspubliclibrary.org', 'TEST', 'This is a test email')
-
-    return render_template('index.html')
+# Encrypt the password with SHA256
+def encrypt_password(password):
+    hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
+    return hash
 
 
-# on exit of the program make sure the http server is stopped
-#@app.teardown_appcontext
 def shutdown_session(exception=None):
     print('Stopping HTTP Service...')
     http_server.stop()
@@ -62,6 +85,156 @@ def get_ip_address():
     return socket.gethostbyname(socket.gethostname())
 
 
+# Method to check if a URL is valid
+def is_valid_url(url):
+    try:
+        result = urlparse(url)
+        return all([result.scheme, result.netloc])
+    except:
+        return False
+
+def requires_auth():
+    print('Checking for session...')
+    if 'username' in session:
+        print('Username in session')
+        username = session['username']
+        user = User.get(User.username == username)
+        if user.logged_in is True:
+            return True
+        else:
+            print('1')
+            return False
+    else:
+        print('2')
+        return False
+
+
+# Check for DB tables and create if they don't exist
+if db.table_exists('user') is False:
+    db.create_tables([User, IlsUser])
+    User.create(username='admin', password=encrypt_password('admin'))
+
+if db.table_exists('ilsuser') is False:
+    db.create_tables([IlsUser])
+
+db.close()
+
+app = Flask(__name__)
+app.secret_key = 'super secret key'
+
+@app.before_request
+def before_request():
+    db.connect()
+
+
+@app.after_request
+def after_request(response):
+    db.close()
+    return response
+
+
+# Create a route for the home page
+@app.route('/', methods=['GET', 'POST'])
+def index():
+    # send_email('aday@twinfallspubliclibrary.org', 'TEST', 'This is a test email')
+    error = None
+    reset = False
+    reset_url = is_valid_url(domain_settings['reset_url'])
+    if reset_url is False:
+        error = 'Invalid Reset URL. Please contact your system administrator.'
+
+    if request.method == 'POST':
+        print('POST')
+        username = request.form.get('username')
+
+        # Check for the username in the DB
+        try:
+            user = IlsUser.filter(IlsUser.username == username).first()
+        except Exception as e:
+            print(e)
+            user = None
+
+        if user:
+            # Reset login datetime
+            user.reset_datetime = datetime.datetime.now()
+            user.save()
+            print(reset_url)
+            # Open the reset URL in a new tab if the URL is valid
+            if reset_url is not False:
+                webbrowser.open_new_tab(reset_url)
+                # Set reset to True to pass back to the view to display the correct content back to the user.
+                reset = True
+
+        print(reset_url)
+    context = {
+        'domain': domain_settings['name'],
+        'error': error,
+        'reset': reset,
+        'reset_url:': reset_url,
+    }
+    return render_template('index.html', context=context)
+
+
+# Create a route for admin page
+@app.route('/admin')
+def admin():
+    # Check to see if user is logged in
+    if not requires_auth():
+        return redirect(url_for('login'))
+
+    return render_template('admin.html')
+
+
+@app.route('/logout')
+def logout():
+    if 'username' in session:
+        username = session['username']
+        user = User.get(User.username == username)
+        user.logged_in = False
+        user.save()
+        session.pop('username', None)
+    return redirect(url_for('login'))
+
+
+@app.route('/login', methods=['GET', 'POST'])
+def login():
+    if request.method == 'POST':
+        username = request.form.get('username')
+        password = encrypt_password(request.form.get('password'))
+
+        try:
+            user = User.filter(User.username == username and User.password == password).first()
+        except Exception as e:
+            print(e)
+            user = None
+            session.pop('username', None)
+
+        if user:
+            # Login user
+            session['username'] = request.form.get('username')
+            user.logged_in = True
+            user.save()
+
+            return redirect(url_for('admin'))
+        else:
+            error = 'Invalid Credentials. Please try again.'
+
+        context = {
+            'error': error
+        }
+        return render_template('login.html', context=context)
+
+    context = {
+
+    }
+    return render_template('login.html', context=context)
+
+
+# on exit of the program make sure the http server is stopped
+#@app.teardown_appcontext
+
+
+
 if __name__ == "__main__":
     print("------------------------- Start up -----------------------------")
     print("Starting HTTP Service on port %s..." % http_settings['port'])

BIN
requirements.txt


+ 4 - 0
settings.ini

@@ -10,3 +10,7 @@ port = 587
 username = tfplweb@twinfallspubliclibrary.org
 password = uYP&>m68
 
+[domain]
+name = lynx
+password_check_interval = [60, 80, 85, 88, 89, 90]
+reset_url =

+ 8 - 0
templates/admin.html

@@ -0,0 +1,8 @@
+{% extends 'layout.html' %}
+{% block content %}
+<div class="row">
+    <div class="col">
+        Admin page
+    </div>
+</div>
+{% endblock %}

+ 34 - 0
templates/auth_layout.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>ILS Password Manager</title>
+    <link rel="stylesheet" href="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/css/bootstrap.css') }}">
+    <script src="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/js/bootstrap.bundle.js') }}"></script>
+</head>
+<body>
+<div class="container">
+    <div class="row mt-5">
+        <div class="col-12 text-center">
+            <h1>ILS Password Manager</h1>
+        </div>
+        <div class="col-12">
+            <div class="border rounded shadow mb-3">
+                <ul class="nav nav-pills nav-fill">
+                    <li class="nav-item">
+                        <a class="nav-link rounded-end-0" aria-current="page" href="#">Dashboard</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link rounded-0" href="#">Accounts</a>
+                    </li>
+                    <li class="nav-item ">
+                        <a class="nav-link rounded-start-0" href="#">Settings</a>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    {% block content %}{% endblock %}
+</div>
+</body>
+</html>

+ 53 - 3
templates/index.html

@@ -1,8 +1,58 @@
 {% extends 'layout.html' %}
 {% block content %}
-<div class="row">
-    <div class="col">
-        Index page
+<div class="row justify-content-center mt-5">
+    <div class="col-sm-12 col-md-8 col-lg-6">
+        <div class="card shadow">
+            <div class="card-body">
+                {% if context.reset_url == False %}
+                    ILS Reset URL not valid. Please contact your system administrator.
+                {% else %}
+                    {% if context.reset == False %}
+                        <p class="lead">
+                            ILS passwords expire every 90 days. Be sure to complete this entire process to ensure your password is reset correctly.
+                        </p>
+                        <ol>
+                            <li class="mb-3">Provide your ILS account username.</li>
+                            <li class="mb-3">Click on the "Start ILS Password Reset" button to be directed to the Lynx Terminal web page.</li>
+                            <li>Log into the {{ context.domain }} terminal web page using your current credentials.</li>
+                            <li class="mb-3">Once logged in, click on the link to reset your password.</li>
+                            <li class="mb-3">Complete the required form to complete the password reset process.
+                                <br><b>Note:</b> <i>domain/user name</i> field needs to be in the following format: <code style="display:block; padding-top:10px; font-size:1.25em;">{{ context.domain }}/username</code></li>
+                        </ol>
+                        <div class="text-center">
+                            <form action="/" method="post">
+                                {% if context.error %}
+                                    <div class="text-danger text-center">
+                                        {{ context.error }}
+                                    </div>
+                                {% endif %}
+
+
+                                <div class="mb-3 text-center mt-2">
+                                    <input type="text" class="form-control" id="username" name="username" placeholder="ILS user account" required>
+                                </div>
+                                <div class="text-center mb-1">
+                                    <button type="submit" class="btn btn-primary w-100">Start ILS Password Reset</button>
+                                </div>
+                            </form>
+                        </div>
+                        {% else %}
+                            <div class="text-center">
+                                <h3>Steps to complete</h3>
+                                <p>A new tab should have opened to the {{ context.domain }} terminal website. If not <a href="{{ context.reset_url }}" target="_blank">here</a> to open the terminal page to complete the following steps:</p>
+                            </div>
+                            <ol>
+                                <li class="mb-3">Log into the {{ context.domain }} terminal web page using your current credentials.</li>
+                                <li class="mb-3">Once logged in, click on the link to reset your password.</li>
+                                <li class="mb-3">Complete the required form to complete the password reset process.
+                                    <br><b>Note:</b> <i>domain/user name</i> field needs to be in the following format: <code style="display:block; padding-top:10px; font-size:1.25em;">{{ context.domain }}/username</code></li>
+                            </ol>
+                        {% endif %}
+                {% endif %}
+
+
+            </div>
+        </div>
     </div>
 </div>
 {% endblock %}

+ 3 - 18
templates/layout.html

@@ -6,26 +6,11 @@
     <link rel="stylesheet" href="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/css/bootstrap.css') }}">
     <script src="{{ url_for('static', filename='bootstrap-5.3.0-alpha1-dist/js/bootstrap.bundle.js') }}"></script>
 </head>
-<body>
+<body class="bg-light">
 <div class="container">
-    <div class="row mt-5">
+    <div class="row mt-5 context-justify-center">
         <div class="col-12 text-center">
-            <h1>ILS Password Manager</h1>
-        </div>
-        <div class="col-12">
-            <div class="border rounded shadow mb-3">
-                <ul class="nav nav-pills nav-fill">
-                    <li class="nav-item">
-                        <a class="nav-link rounded-end-0" aria-current="page" href="#">Dashboard</a>
-                    </li>
-                    <li class="nav-item">
-                        <a class="nav-link rounded-0" href="#">Accounts</a>
-                    </li>
-                    <li class="nav-item ">
-                        <a class="nav-link rounded-start-0" href="#">Settings</a>
-                    </li>
-                </ul>
-            </div>
+            <h1>ILS Password Reset Tool</h1>
         </div>
     </div>
     {% block content %}{% endblock %}

+ 24 - 0
templates/login.html

@@ -0,0 +1,24 @@
+
+{% extends "layout.html" %}
+{% block content %}
+    <div class="row mt-5 justify-content-center">
+        <div class="col-sm-12 col-md-6 col-lg-4">
+            <form action="/login" method="post">
+                {% if context.error %}
+                    <div class="text-danger text-center p-4">
+                        {{ context.error }}
+                    </div>
+                {% endif %}
+                <div class="mb-3">
+                    <input type="text" class="form-control" id="username" name="username" placeholder="ILS user account">
+                </div>
+                <div class="mb-3">
+                    <input type="password" class="form-control" id="password" name="password" placeholder="Password">
+                </div>
+                <div class="text-center">
+                    <button type="submit" class="btn btn-lg btn-primary w-100">Login</button>
+                </div>
+            </form>
+        </div>
+    </div>
+{% endblock %}