From b9613a60dee08c152f342ba2ee3cf2261c50f51a Mon Sep 17 00:00:00 2001 From: b3yond Date: Fri, 23 Mar 2018 02:28:00 +0100 Subject: [PATCH] added twitter & masto OAuth to new web.py - untested, take care! --- db.py | 49 +++++++++++++++++++++++------ template/settings.tpl | 6 ++++ ticketfrei-web.py | 71 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 10 deletions(-) diff --git a/db.py b/db.py index 72217ad..9ace8fd 100644 --- a/db.py +++ b/db.py @@ -6,15 +6,13 @@ from os import path, urandom from pylibscrypt import scrypt_mcf, scrypt_mcf_check import sqlite3 import pytoml as toml -import sendmail -import smtplib +from mastodon import Mastodon class DB(object): def __init__(self): dbfile = path.join(path.dirname(path.abspath(__file__)), 'ticketfrei.sqlite') - #dbfile = ':memory:' self.conn = sqlite3.connect(dbfile) self.cur = self.conn.cursor() self.cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='user';") @@ -132,13 +130,6 @@ class DB(object): return None return User(self, row[0]) - def send_confirmation_mail(self, confirm_link, email): - m = sendmail.Mailer(self.config) - try: - m.send("Complete your registration here: " + confirm_link, email, "[Ticketfrei] Confirm your account") - except smtplib.SMTPRecipientsRefused: - return "Please enter a valid E-Mail address." - def close(self): self.conn.close() @@ -153,6 +144,44 @@ class User(object): def state(self): return dict(foo='bar') + def save_request_token(self, token): + self.db.cur.execute("INSERT INTO twitter_request_tokens(user_id, request_token) VALUES(?, ?);", + (self.uid, token)) + self.db.conn.commit() + + def get_request_token(self): + self.db.cur.execute("SELECT request_token FROM twitter_request_tokens WHERE user_id = ?;", (id,)) + request_token = self.db.cur.fetchone()[0] + self.db.cur.execute("DELETE FROM twitter_request_tokens WHERE user_id = ?;", (id,)) + self.db.conn.commit() + return request_token + + def save_twitter_token(self, access_token, access_token_secret): + self.db.cur.execute( + "INSERT INTO twitter_accounts(user_id, access_token_key, access_token_secret) VALUES(?, ?, ?);", + (id, access_token, access_token_secret)) + self.db.conn.commit() + + def get_mastodon_app_keys(self, instance): + self.db.cur.execute("SELECT client_id, client_secret FROM mastodon_instances WHERE instance = ?;", (instance, )) + try: + client_id, client_secret = self.db.cur.fetchone()[0] + return client_id, client_secret + except TypeError: + app_name = "ticketfrei" + str(self.db.secret)[0:4] + client_id, client_secret = Mastodon.create_app(app_name, api_base_url=instance) + self.db.cur.execute("INSERT INTO mastodon_instances(instance, client_id, client_secret) VALUES(?, ?, ?);", + (instance, client_id, client_secret)) + self.db.conn.commit() + return client_id, client_secret + + def save_masto_token(self, access_token, instance): + self.db.cur.execute("SELECT id FROM mastodon_instances WHERE instance = ?;", (instance, )) + instance_id = self.db.cur.fetchone()[0] + self.db.cur.execute("INSERT INTO mastodon_accounts(user_id, access_token, mastodon_instances_id, active) " + "VALUES(?, ?, ?, ?);", (self.uid, access_token, instance_id, 1)) + self.db.commit() + class DBPlugin(object): name = 'DBPlugin' diff --git a/template/settings.tpl b/template/settings.tpl index c77ec72..1d34116 100644 --- a/template/settings.tpl +++ b/template/settings.tpl @@ -16,6 +16,12 @@

Log in with Mastodon

+ + + + + + diff --git a/ticketfrei-web.py b/ticketfrei-web.py index 5d93371..d176ef3 100644 --- a/ticketfrei-web.py +++ b/ticketfrei-web.py @@ -1,6 +1,10 @@ import bottle from bottle import get, post, redirect, request, response, view from db import DBPlugin +import tweepy +import sendmail +import smtplib +from mastodon import Mastodon @get('/') @@ -8,6 +12,7 @@ from db import DBPlugin def propaganda(): pass + @post('/register', db='db') @view('template/register.tpl') def register_post(db): @@ -24,6 +29,14 @@ def register_post(db): return dict(info='Confirmation mail sent.') +def send_confirmation_mail(self, confirm_link, email): + m = sendmail.Mailer(self.config) + try: + m.send("Complete your registration here: " + confirm_link, email, "[Ticketfrei] Confirm your account") + except smtplib.SMTPRecipientsRefused: + return "Please enter a valid E-Mail address." + + @get('/confirm/', db='db') @view('template/propaganda.tpl') def confirm(db, token): @@ -59,6 +72,7 @@ def api_enable(user): def static(filename): return bottle.static_file(filename, root='static') + @get('/logout/') def logout(): # clear auth cookie @@ -67,5 +81,62 @@ def logout(): return redirect('/') +@get('/login/twitter', user='user') +def login_twitter(user): + """ + Starts the twitter OAuth authentication process. + :return: redirect to twitter. + """ + consumer_key = user.db.config["tapp"]["consumer_key"] + consumer_secret = user.db.config["tapp"]["consumer_secret"] + callback_url = bottle.request.get_header('host') + "/login/twitter/callback" + auth = tweepy.OAuthHandler(consumer_key, consumer_secret, callback_url) + try: + redirect_url = auth.get_authorization_url() + except tweepy.TweepError: + return 'Error! Failed to get request token.' + user.save_request_token(auth.request_token) + return bottle.redirect(redirect_url) + + +@get('/login/twitter/callback', user="user") +def twitter_callback(user): + """ + Gets the callback + :return: + """ + # twitter passes the verifier/oauth token secret in a GET request. + verifier = bottle.request.query('oauth_verifier') + consumer_key = user.db.config["tapp"]["consumer_key"] + consumer_secret = user.db.config["tapp"]["consumer_secret"] + auth = tweepy.OAuthHandler(consumer_key, consumer_secret) + request_token = user.get_request_token + auth.request_token = {"oauth_token": request_token, + "oauth_token_secret": verifier} + auth.get_access_token(verifier) + user.save_twitter_token(auth.access_token, auth.access_token_secret) + return bottle.redirect("/settings") + + +@post('/login/mastodon', user="user") +def login_mastodon(user): + """ + Starts the mastodon OAuth authentication process. + :return: redirect to twitter. + """ + # get app tokens + instance_url = bottle.request.forms.get('instance_url') + masto_email = bottle.request.forms.get('email') + masto_pass = bottle.request.forms.get('password') + client_id, client_secret = user.get_mastodon_app_keys(instance_url) + m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=instance_url) + try: + access_token = m.log_in(masto_email, masto_pass) + user.save_masto_token(access_token, instance_url) + return dict(info='Thanks for supporting decentralized social networks!') + except: + return dict(error='Login to Mastodon failed.') + + bottle.install(DBPlugin('/')) bottle.run(host='localhost', port=8080)