From 556dea9fae1ad5cf297296a78643cc27883f1543 Mon Sep 17 00:00:00 2001 From: Lynne Date: Mon, 2 Sep 2019 13:07:46 +1000 Subject: [PATCH] authentication worksgit status --- static/style.css | 1 - templates/bot_create.html | 5 ++- webui.py | 90 +++++++++++++++++++++++++++++++++++---- 3 files changed, 86 insertions(+), 10 deletions(-) diff --git a/static/style.css b/static/style.css index 560055c..ec7bc3a 100644 --- a/static/style.css +++ b/static/style.css @@ -135,7 +135,6 @@ h1, h2, h3, h4, h5, h6 { } form { - text-align: justify; display:inline-block; } label.important { diff --git a/templates/bot_create.html b/templates/bot_create.html index f213c2e..533e391 100644 --- a/templates/bot_create.html +++ b/templates/bot_create.html @@ -9,7 +9,6 @@

Create bot

-

Step {{ session['step'] }}

@@ -43,7 +42,11 @@ {% if session['step'] != 1 %} {% endif %} + {% if session['step'] < 5 %} + {% else %} + Finish + {% endif %}
diff --git a/webui.py b/webui.py index 7eaf6d3..764dd7b 100644 --- a/webui.py +++ b/webui.py @@ -1,5 +1,6 @@ from flask import Flask, render_template, session, request, redirect, url_for from flask_mysqldb import MySQL +from mastodon import Mastodon import requests import MySQLdb import bcrypt @@ -17,16 +18,18 @@ app.config['MYSQL_PASSWORD'] = cfg['db_pass'] mysql = MySQL(app) +scopes = ['write:statuses', 'write:accounts', 'read:accounts', 'read:notifications', 'read:statuses'] + @app.route("/") def home(): - if 'userid' in session: + if 'user_id' in session: session['step'] = 1 c = mysql.connection.cursor() - c.execute("SELECT COUNT(*) FROM `bots` WHERE user_id = %s", (session['userid'],)) + c.execute("SELECT COUNT(*) FROM `bots` WHERE user_id = %s", (session['user_id'],)) bot_count = c.fetchone()[0] active_count = None if bot_count > 0: - c.execute("SELECT COUNT(*) FROM `bots` WHERE user_id = %s AND enabled = TRUE", (session['userid'],)) + c.execute("SELECT COUNT(*) FROM `bots` WHERE user_id = %s AND enabled = TRUE", (session['user_id'],)) active_count = c.fetchone()[0] c.close() return render_template("home.html", bot_count = bot_count, active_count = active_count) @@ -72,6 +75,7 @@ def bot_accounts_add(): @app.route("/bot/create/", methods=['GET', 'POST']) def bot_create(): + #TODO: error handling if request.method == 'POST': if session['step'] == 1: # strip leading https://, if provided @@ -101,10 +105,81 @@ def bot_create(): session['error'] = "Unsupported instance type." elif session['step'] == 2: - pass + # nothing needs to be done here, this step just informs the user that their instance type is supported + session['step'] += 1 + + elif session['step'] == 3: + # authenticate with the given instance and obtain credentials + if session['instance_type'] in ['Mastodon', 'Pleroma']: + redirect_uri = '{}/do/authenticate_bot'.format(cfg['base_uri']) + + session['client_id'], session['client_secret'] = Mastodon.create_app( + "FediBooks", + api_base_url="https://{}".format(session['instance']), + scopes=scopes, + redirect_uris=[redirect_uri], + website=cfg['base_uri'] + ) + + client = Mastodon( + client_id=session['client_id'], + client_secret=session['client_secret'], + api_base_url="https://{}".format(session['instance']) + ) + + url = client.auth_request_url(client_id=session['client_id'], redirect_uris=redirect_uri, scopes=scopes) + return redirect(url, code=303) + + elif session['instance_type'] == 'Misskey': + # todo + pass + + else: + # the user clicked next on step 2 while having an unsupported instance type + # take them back to step 1 + del session['instance'] + del session['instance_type'] + session['step'] = 1 + return bot_create() + + elif session['step'] == 4: + try: + # test authentication + client = Mastodon(client_id=session['client_id'], client_secret=session['client_secret'], api_base_url=session['instance']) + session['secret'] = client.log_in(code = session['code'], scopes=scopes, redirect_uri='{}/do/authenticate_bot'.format(cfg['base_uri'])) + username = client.account_verify_credentials()['username'] + handle = "@{}@{}".format(username, session['instance']) + except: + # authentication error occurred + return render_template("bot_oauth_error.html") + + # authentication success!! + c = mysql.connection.cursor() + c.execute("INSERT INTO `credentials` (client_id, client_secret, secret) VALUES (%s, %s, %s)", (session['client_id'], session['client_secret'], session['code'])) + credentials_id = c.lastrowid + mysql.connection.commit() + + bot_id = hashlib.sha256(handle.encode('utf-8')).digest() + c.execute("INSERT INTO `bots` (id, user_id, credentials_id, handle) VALUES (%s, %s, %s, %s)", (bot_id, session['user_id'], credentials_id, handle)) + mysql.connection.commit() + + c.close() + + # clean up unneeded variables + del session['code'] + del session['instance'] + del session['instance_type'] + del session['client_id'] + del session['client_secret'] return render_template("bot_create.html") +@app.route("/do/authenticate_bot") +def do_authenticate_bot(): + session['code'] = request.args.get('code') + session['step'] = 4 + return redirect(url_for("bot_create"), 303) + @app.route("/do/signup", methods=['POST']) def do_signup(): # email validation is basically impossible without actually sending an email to the address @@ -115,19 +190,18 @@ def do_signup(): if len(request.form['password']) < 8: return show_signup_page("Password too short.") - user_id = hashlib.sha256(request.form['email'].encode('utf-8')).digest() - pw_hashed = hashlib.sha256(request.form['password'].encode('utf-8')).digest() pw = bcrypt.hashpw(pw_hashed, bcrypt.gensalt(12)) # try to sign up c = mysql.connection.cursor() c.execute("INSERT INTO `users` (email, password) VALUES (%s, %s)", (request.form['email'], pw)) + user_id = c.lastrowid mysql.connection.commit() c.close() # success! - session['userid'] = user_id + session['user_id'] = user_id return redirect(url_for('home')) @app.route("/do/signout") @@ -143,7 +217,7 @@ def do_login(): data = c.fetchone() c.close() if bcrypt.checkpw(pw_hashed, data['password']): - session['userid'] = data['id'] + session['user_id'] = data['id'] return redirect(url_for("home")) else: