1
0
mirror of https://github.com/Adam-Ant/QuotesDB synced 2024-12-20 11:34:35 +00:00

Add username/password authentication system

This commit is contained in:
Adam Dodman 2017-10-04 01:04:18 +01:00
parent 679a2d872e
commit 54afcfad1d
3 changed files with 119 additions and 10 deletions

73
adduser.py Normal file
View File

@ -0,0 +1,73 @@
import pymysql
import getpass
import sys
from passlib.context import CryptContext
user = realname = passwd = None
pass_ctx = CryptContext(["bcrypt_sha256"])
# https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input
def query_yes_no(question, default="yes"):
"""Ask a yes/no question via raw_input() and return their answer.
"question" is a string that is presented to the user.
"default" is the presumed answer if the user just hits <Enter>.
It must be "yes" (the default), "no" or None (meaning
an answer is required of the user).
The "answer" return value is True for "yes" or False for "no".
"""
valid = {"yes": 1, "y": 1, "ye": 1,
"no": 0, "n": 0}
if default is None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while True:
sys.stdout.write(question + prompt)
choice = input().lower()
if default is not None and choice == '':
return valid[default]
elif choice in valid:
return valid[choice]
else:
sys.stdout.write("Please respond with 'yes' or 'no' "
"(or 'y' or 'n').\n")
while not user:
user = input("Enter Username: ")
while not realname:
realname = input("Enter the real name of the user: ")
while not passwd:
passwd = getpass.getpass()
passwd_v = getpass.getpass(prompt="Reenter password: ")
while passwd != passwd_v:
print ("Error: Passwords do not match!")
passwd = getpass.getpass()
passwd_v = getpass.getpass()
passwd_hash = pass_ctx.hash(passwd)
isadmin = query_yes_no("Is the user an admin?", "no")
query = "INSERT INTO `Users` (`uid`, `user`, `realname`, `password`, `isadmin`) VALUES (NULL, '%s', '%s', '%s', %d);" % (user, realname, passwd_hash, isadmin)
db = pymysql.connect(host='dockerdev', port=3306, user='root', passwd='development', db='QuoteDB')
cur = db.cursor()
cur.execute(query)
data = cur.fetchall()
cur.close()
db.commit()
db.close()

View File

@ -1,9 +1,9 @@
CREATE TABLE Users (
uid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
user VARCHAR(255) NOT NULL,
user VARCHAR(255) NOT NULL UNIQUE,
realname VARCHAR(255) NOT NULL,
password VARCHAR(255),
isadmin BIT
isadmin BIT NOT NULL
);
CREATE TABLE Quotes (

52
main.py
View File

@ -1,18 +1,23 @@
from os import urandom as rand
from flaskext.mysql import MySQL
#from flaskext.mysql import MySQL
import pymysql
from flask import Flask, render_template, session, redirect, url_for, request, flash
from passlib.context import CryptContext
import pprint
pp = pprint.PrettyPrinter(indent=4)
pass_ctx = CryptContext(["bcrypt_sha256"])
app = Flask(__name__)
# Thank you based StackOverflow
# Remove Trailing and leading whitespace, strip unicode
def cleanup_string(text):
text = text.encode("ascii", "replace").decode()
return text.strip()
# Load User Table into variable
def mysql_do(query):
db = pymysql.connect(host='dockerdev', port=3306, user='root', passwd='development', db='QuoteDB')
@ -25,13 +30,37 @@ def mysql_do(query):
return data
def app_init():
mysql_do("CREATE TABLE IF NOT EXISTS Users ( uid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, user VARCHAR(255) NOT NULL, realname VARCHAR(255) NOT NULL, password VARCHAR(255), isadmin BIT );")
# Check to make sure tables are set up properly
mysql_do("CREATE TABLE IF NOT EXISTS Users ( uid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, user VARCHAR(255) NOT NULL UNIQUE, realname VARCHAR(255) NOT NULL, password VARCHAR(255), isadmin BIT NOT NULL);")
mysql_do("CREATE TABLE IF NOT EXISTS Quotes ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, quote VARCHAR(2048) NOT NULL, date VARCHAR(255) NOT NULL, user INT NOT NULL, context VARCHAR(8000), FOREIGN KEY (user) REFERENCES Users(uid) );")
# Generate random key for session cookies
app.secret_key = rand(24)
# TODO: Replace this with something dynamic where needed
global userdb
userdb = mysql_do("SELECT * FROM Users")
def do_user_login(user, password):
try:
userdata = mysql_do("SELECT * FROM Users WHERE user='%s'" % (user))[0]
except IndexError:
# Returned when no rows found - no user with that name
flash( "Error: Incorrect Username or Password!", "danger")
return redirect(url_for('login'))
if pass_ctx.verify(password, userdata[3]):
session['username'] = user
session['uid'] = userdata[0]
session['isAdmin'] = bool(ord(userdata[4]))
return redirect(url_for('index'))
else:
flash( "Error: Incorrect Username or Password!", "danger")
return redirect(url_for('login'))
@app.route("/")
def index():
if 'username' in session:
@ -43,6 +72,12 @@ def quoutepage():
retdata = mysql_do("SELECT * FROM Quotes ORDER BY ID DESC")
return render_template("quote_view.html", data=retdata)
@app.route("/login", methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_user_login(request.form['username'], request.form['pw'])
return render_template("login.html")
@app.route("/addquote", methods=['GET','POST'])
def addquote():
if request.method == "POST":
@ -90,14 +125,15 @@ def addquote():
mysql_do(sql)
flash("Success! The entry was added to the database.","success")
return redirect(url_for('index'))
# Check if the user is authenticated
try:
session['username']
except KeyError:
flash("INFO: Please login first.","info")
return redirect(url_for("login"))
return render_template("add_quote.html", users=userdb)
@app.route("/login", methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return render_template("login.html")
@app.route("/logout")
def logout():