added twitter & masto OAuth to new web.py - untested, take care!

This commit is contained in:
b3yond 2018-03-23 02:28:00 +01:00
parent 235b8524f8
commit b9613a60de
3 changed files with 116 additions and 10 deletions

49
db.py
View file

@ -6,15 +6,13 @@ from os import path, urandom
from pylibscrypt import scrypt_mcf, scrypt_mcf_check from pylibscrypt import scrypt_mcf, scrypt_mcf_check
import sqlite3 import sqlite3
import pytoml as toml import pytoml as toml
import sendmail from mastodon import Mastodon
import smtplib
class DB(object): class DB(object):
def __init__(self): def __init__(self):
dbfile = path.join(path.dirname(path.abspath(__file__)), dbfile = path.join(path.dirname(path.abspath(__file__)),
'ticketfrei.sqlite') 'ticketfrei.sqlite')
#dbfile = ':memory:'
self.conn = sqlite3.connect(dbfile) self.conn = sqlite3.connect(dbfile)
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
self.cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='user';") self.cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='user';")
@ -132,13 +130,6 @@ class DB(object):
return None return None
return User(self, row[0]) 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): def close(self):
self.conn.close() self.conn.close()
@ -153,6 +144,44 @@ class User(object):
def state(self): def state(self):
return dict(foo='bar') 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): class DBPlugin(object):
name = 'DBPlugin' name = 'DBPlugin'

View file

@ -16,6 +16,12 @@
<h2>Log in with Mastodon</h2> <h2>Log in with Mastodon</h2>
<p> <p>
<form action="/login/mastodon" method='post'> <form action="/login/mastodon" method='post'>
<label for="email">E-Mail of your Mastodon-Account</label>
<input type="text" placeholder="Enter Email" name="email" id="email" required>
<label for="pass">Mastodon Password</label>
<input type="password" placeholder="Enter Password" name="pass" id="pass" required>
<label>Mastodon instance: <label>Mastodon instance:
<input type='text' name='instance_url' list='instances' placeholder='social.example.net'/> <input type='text' name='instance_url' list='instances' placeholder='social.example.net'/>
</label> </label>

View file

@ -1,6 +1,10 @@
import bottle import bottle
from bottle import get, post, redirect, request, response, view from bottle import get, post, redirect, request, response, view
from db import DBPlugin from db import DBPlugin
import tweepy
import sendmail
import smtplib
from mastodon import Mastodon
@get('/') @get('/')
@ -8,6 +12,7 @@ from db import DBPlugin
def propaganda(): def propaganda():
pass pass
@post('/register', db='db') @post('/register', db='db')
@view('template/register.tpl') @view('template/register.tpl')
def register_post(db): def register_post(db):
@ -24,6 +29,14 @@ def register_post(db):
return dict(info='Confirmation mail sent.') 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/<token>', db='db') @get('/confirm/<token>', db='db')
@view('template/propaganda.tpl') @view('template/propaganda.tpl')
def confirm(db, token): def confirm(db, token):
@ -59,6 +72,7 @@ def api_enable(user):
def static(filename): def static(filename):
return bottle.static_file(filename, root='static') return bottle.static_file(filename, root='static')
@get('/logout/') @get('/logout/')
def logout(): def logout():
# clear auth cookie # clear auth cookie
@ -67,5 +81,62 @@ def logout():
return redirect('/') 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.install(DBPlugin('/'))
bottle.run(host='localhost', port=8080) bottle.run(host='localhost', port=8080)