diff --git a/db/sqlite.py b/db/sqlite.py index f1ebaf6..f096ae6 100644 --- a/db/sqlite.py +++ b/db/sqlite.py @@ -49,5 +49,44 @@ class DB: return str(parent) + str(children) return parent + def get_user_password(self, username): + return self._db().execute(''' + select user_id, password + from users + where name = ? + ''', + (username,) + ).fetchone() + + def get_user_public_info(self, user_id): + return self._db().execute(''' + select name, about + from users + where user_id = ? + ''', + (user_id,) + ).fetchone() + + def get_user_private_info(self, user_id): + return self._db().execute(''' + select about + from users + where user_id = ? + ''', + (user_id,) + ).fetchone() + + def set_user_private_info(self, user_id, about): + print('BROH', about) + db = self._db() + db.execute(''' + update users + set about = ? + where user_id = ? + ''', + (about, user_id) + ) + db.commit() + def _db(self): return sqlite3.connect(self.conn) diff --git a/main.py b/main.py index 23d336f..78e61cf 100644 --- a/main.py +++ b/main.py @@ -1,32 +1,88 @@ -from flask import Flask, render_template +from flask import Flask, render_template, session, request, redirect, url_for, flash from db.sqlite import DB import os +import passlib.hash +import time app = Flask(__name__) db = DB(os.getenv('DB')) NAME = 'Agrepy' +# TODO config file +app.config['SECRET_KEY'] = 'totally random' + @app.route('/') def index(): return render_template('index.html', title = NAME, subforums = db.get_subforums()) -@app.route('/forum//') +@app.route('/forum//') def subforum(forum_id): title, description = db.get_subforum(forum_id) threads = db.get_threads(forum_id) return render_template('subforum.html', title = title, description = description, threads = threads) -@app.route('/thread//') +@app.route('/thread//') def thread(thread_id): title, text, author, comments = db.get_thread(thread_id) comments = create_comment_tree(comments) return render_template('thread.html', title = title, text = text, author = author, comments = comments) -@app.route('/comment//') +@app.route('/comment//') def comment(comment_id): #return str(db.get_comment_tree(comment_id)[0]) return str(db.get_comment_tree(comment_id)) +@app.route('/login/', methods = ['GET', 'POST']) +def login(): + if request.method == 'POST': + v = db.get_user_password(request.form['username']) + if v is not None: + id, hash = v + if passlib.hash.argon2.verify(request.form['password'], hash): + flash('Logged in', 'success') + session['user_id'] = id + session['username'] = request.form['username'] + return redirect(url_for('index')) + else: + # Sleep to reduce effectiveness of bruteforce + time.sleep(0.1) + flash('Username or password is invalid', 'error') + return render_template('login.html', title = "Login") + return render_template('login.html', title = "Login") + +@app.route('/logout/') +def logout(): + session.pop('user_id') + return redirect(url_for('index')) + +@app.route('/user/', methods = ['GET', 'POST']) +def user_edit(): + user_id = session.get('user_id') + if user_id is None: + return redirect(url_for('login')) + + if request.method == 'POST': + about = request.form['about'] + db.set_user_private_info(user_id, about) + else: + about, = db.get_user_private_info(user_id) + + return render_template( + 'user_edit.html', + name = session.get('username', '???'), + title = 'Edit profile', + about = about + ) + +@app.route('/user/') +def user_info(user_id): + name, about = db.get_user_public_info(user_id) + return render_template( + 'user_info.html', + title = 'Profile', + name = name, + about = about + ) class Comment: def __init__(self, author, text): diff --git a/schema.txt b/schema.txt index 3e69eb4..8639a9f 100644 --- a/schema.txt +++ b/schema.txt @@ -3,7 +3,7 @@ create table users ( name varchar(32) unique not null, password varchar(128) not null, email varchar(254), - about text, + about text not null default '', join_date integer, role integer not null default 0 ); diff --git a/templates/base.html b/templates/base.html index bf64e8a..618d6b1 100644 --- a/templates/base.html +++ b/templates/base.html @@ -5,8 +5,18 @@

{{ title }}

+ {% for category, msg in get_flashed_messages(True) %} +

{{ category}}: {{ msg }}

+ {% endfor %}
{% block content %}{% endblock %}
diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..9180fbd --- /dev/null +++ b/templates/login.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block content %} +
+

Username:

+

Password:

+ +
+{% endblock %} diff --git a/templates/user_edit.html b/templates/user_edit.html new file mode 100644 index 0000000..f32fd7d --- /dev/null +++ b/templates/user_edit.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block content %} +
+

{{ name }}

+ + +
+{% endblock %} diff --git a/templates/user_info.html b/templates/user_info.html new file mode 100644 index 0000000..402a2ee --- /dev/null +++ b/templates/user_info.html @@ -0,0 +1,6 @@ +{% extends 'base.html' %} + +{% block content %} +

{{ name }}

+

{{ about }}

+{% endblock %} diff --git a/test/init_db.txt b/test/init_db.txt index e5c9f64..dcefd30 100644 --- a/test/init_db.txt +++ b/test/init_db.txt @@ -1,6 +1,20 @@ -insert into users (name, password, email) values ("Foo", "supasecret", "foo@bar.baz"); -insert into users (name, password, email) values ("Bar", "rgjieogir", "bar@foo.baz"); -insert into users (name, password) values ("bazzers", "reogke"); +insert into users (name, password, email) values ( + "Foo", + -- supasecret + "$argon2id$v=19$m=65536,t=3,p=4$qBWCEAKgdA4BYOy915qzlg$KhGy3UF0QMlplt2eB7r7QNL2kDcggXUimRWUrWql8sI", + "foo@bar.baz" +); +insert into users (name, password, email) values ( + "Bar", + -- abraca + "$argon2id$v=19$m=65536,t=3,p=4$klJKCUFoDaF07j3nPCeEUA$lCphd5n1YIs8MaVop2vGNirwknkh91qJIZHMuBOlgWA", + "bar@foo.baz" +); +insert into users (name, password) values ( + "bazzers", + -- e + "$argon2id$v=19$m=65536,t=3,p=4$9v5fS2ktxTinNEbIGUOoFQ$LMdEuAuuTCJ7utOE88+nXn7o6R/DEKY8ZA6wV+YkVGQ" +); insert into subforums (name, description, allowed_roles_mask) values ("Earth", "The totality of all space and time; all that is, has been, and will be.", 1);