forked from ticketfrei/ticketfrei
175 lines
6.3 KiB
Python
175 lines
6.3 KiB
Python
from bottle import redirect, request
|
|
from functools import wraps
|
|
from inspect import Signature
|
|
import jwt
|
|
import logging
|
|
from os import urandom
|
|
from pylibscrypt import scrypt_mcf, scrypt_mcf_check
|
|
import sqlite3
|
|
from user import User
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class DB(object):
|
|
def __init__(self, dbfile):
|
|
self.conn = sqlite3.connect(dbfile)
|
|
self.cur = self.conn.cursor()
|
|
self.create()
|
|
self.secret = urandom(32)
|
|
|
|
def create(self):
|
|
# init db
|
|
self.cur.executescript('''
|
|
CREATE TABLE IF NOT EXISTS user (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
email TEXT,
|
|
passhash TEXT,
|
|
enabled INTEGER DEFAULT 1
|
|
);
|
|
CREATE TABLE IF NOT EXISTS twitter_request_tokens (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
request_token TEXT,
|
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS twitter_accounts (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
client_id TEXT,
|
|
client_secret TEXT,
|
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS trigger_good (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
words TEXT,
|
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS trigger_bad (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
words TEXT,
|
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS mastodon_instances (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
instance TEXT,
|
|
client_id TEXT,
|
|
client_secret TEXT
|
|
);
|
|
CREATE TABLE IF NOT EXISTS mastodon_accounts (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
access_token TEXT,
|
|
instance_id TEXT,
|
|
active INTEGER,
|
|
FOREIGN KEY(user_id) REFERENCES user(id),
|
|
FOREIGN KEY(instance_id) REFERENCES mastodon_instances(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS seen_toots (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
mastodon_accounts_id INTEGER,
|
|
toot_id TEXT,
|
|
FOREIGN KEY(user_id) REFERENCES user(id),
|
|
FOREIGN KEY(mastodon_accounts_id)
|
|
REFERENCES mastodon_accounts(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS mail (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
email TEXT,
|
|
active INTEGER,
|
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS seen_mails (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
mail_id INTEGER,
|
|
mail_date INTEGER,
|
|
FOREIGN KEY(user_id) REFERENCES user(id),
|
|
FOREIGN KEY(mail_id) REFERENCES mail(id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS seen_tweets (
|
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
user_id INTEGER,
|
|
twitter_accounts_id INTEGER,
|
|
tweet_id TEXT,
|
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
|
FOREIGN KEY(twitter_accounts_id)
|
|
REFERENCES twitter_accounts(id)
|
|
);
|
|
''')
|
|
|
|
def token(self, email, password):
|
|
return jwt.encode({
|
|
'email': email,
|
|
'passhash': scrypt_mcf(password.encode('utf-8')).decode('ascii')
|
|
}, self.secret).decode('ascii')
|
|
|
|
def register(self, token):
|
|
json = jwt.decode(token, self.secret)
|
|
# create user
|
|
self.cur.execute("INSERT INTO user (email, passhash) VALUES(?, ?);",
|
|
(json['email'], json['passhash']))
|
|
self.conn.commit()
|
|
return User(self, self.cur.lastrowid)
|
|
|
|
def authenticate(self, email, password):
|
|
# check email/password
|
|
self.cur.execute("SELECT id, passhash FROM user WHERE email=?;",
|
|
(email, ))
|
|
row = self.cur.fetchone()
|
|
if not row:
|
|
return None # No user with this email
|
|
if not scrypt_mcf_check(row[1].encode('ascii'),
|
|
password.encode('utf-8')):
|
|
return None # Wrong passphrase
|
|
return User(self, row[0])
|
|
|
|
def by_email(self, email):
|
|
self.cur.execute("SELECT id FROM user WHERE email=?;", (email, ))
|
|
row = self.cur.fetchone()
|
|
if not row:
|
|
return None
|
|
return User(self, row[0])
|
|
|
|
def close(self):
|
|
self.conn.close()
|
|
|
|
def get_users(self):
|
|
self.cur.execute("SELECT id FROM user WHERE enabled=1;")
|
|
return self.cur.fetchall()
|
|
|
|
|
|
class DBPlugin(object):
|
|
name = 'DBPlugin'
|
|
api = 2
|
|
|
|
def __init__(self, dbfile, loginpage):
|
|
self.db = DB(dbfile)
|
|
self.loginpage = loginpage
|
|
|
|
def close(self):
|
|
self.db.close()
|
|
|
|
def apply(self, callback, route):
|
|
uservar = route.config.get('user', None)
|
|
dbvar = route.config.get('db', None)
|
|
signature = Signature.from_callable(route.callback)
|
|
|
|
@wraps(callback)
|
|
def wrapper(*args, **kwargs):
|
|
if uservar and uservar in signature.parameters:
|
|
uid = request.get_cookie('uid', secret=self.db.secret)
|
|
if uid is None:
|
|
return redirect(self.loginpage)
|
|
kwargs[uservar] = User(self.db, uid)
|
|
if dbvar and dbvar in signature.parameters:
|
|
kwargs[dbvar] = self.db
|
|
return callback(*args, **kwargs)
|
|
|
|
return wrapper
|