From 4f1561105d885cda4545e204da178b51169d561c Mon Sep 17 00:00:00 2001 From: Lynne Date: Wed, 14 Nov 2018 01:11:59 +1000 Subject: [PATCH] never leave DB open --- run.py | 2 +- web.py | 28 +++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/run.py b/run.py index 9195987..76a7ec4 100755 --- a/run.py +++ b/run.py @@ -41,7 +41,7 @@ for row in dc.fetchall(): #this is the one we've already seen continue - toot = "Curious Cat user {} asks: {}\nMy answer: {}\https://curiouscat.me/{}/post/{}".format(sender, post['comment'], post['reply'], row['cc'], post['id']) #TODO: what if this is over 500 characters? + toot = "Curious Cat user {} asks: {}\nMy answer: {}https://curiouscat.me/{}/post/{}".format(sender, post['comment'], post['reply'], row['cc'], post['id']) #TODO: what if this is over 500 characters? if settings['cw']: client.status_post(toot, spoiler_text="Curious Cat post") else: diff --git a/web.py b/web.py index 4123451..3273346 100755 --- a/web.py +++ b/web.py @@ -20,9 +20,6 @@ settings = { # "disabled": False, } -db = mysql.connector.connect(user=cfg['dbuser'], password=cfg['dbpass'], database=cfg['dbname']) -c = db.cursor() -dc = db.cursor(dictionary=True) # +---------------------+---------------+------+-----+------------------------------------------------+-------+ # | Field | Type | Null | Key | Default | Extra | # +---------------------+---------------+------+-----+------------------------------------------------+-------+ @@ -40,7 +37,16 @@ dc = db.cursor(dictionary=True) # | time_between_checks | int(11) | NO | | 1 | | # | settings | varchar(4096) | YES | | {"cw": true} | | # +---------------------+---------------+------+-----+------------------------------------------------+-------+ + +def db_reconnect(): + db = mysql.connector.connect(user=cfg['dbuser'], password=cfg['dbpass'], database=cfg['dbname']) + c = db.cursor() + dc = db.cursor(dictionary=True) + return (db, c, dc) + +db, c, dc = db_reconnect() c.execute("CREATE TABLE IF NOT EXISTS `data` (username VARCHAR(64) NOT NULL, instance VARCHAR(128) NOT NULL, password TINYTEXT NOT NULL, avi TEXT NOT NULL, secret TINYTEXT NOT NULL, client_id VARCHAR(128) NOT NULL, client_secret TINYTEXT NOT NULL, cc TINYTEXT, ccavi VARCHAR(128) DEFAULT 'https://lynnesbian.space/res/ceres/cc-smol.png', latest_post TINYTEXT, last_check INT DEFAULT 0 NOT NULL, time_between_checks INT DEFAULT %s NOT NULL, settings VARCHAR(4096) DEFAULT %s, PRIMARY KEY(username, instance))", (cfg['min_time_between_checks'], json.dumps(settings),)) +db.close() app = Flask(cfg['name']) app.secret_key = cfg['flask_key'] @@ -55,12 +61,14 @@ def main(): @app.route('/home') def home(): if 'acct' in session: + db, c, dc = db_reconnect() dc.execute("SELECT * FROM data WHERE username = %s AND instance = %s", (session['username'], session['instance'])) data = dc.fetchone() try: for item in ['username', 'instance', 'avi', 'secret', 'client_id', 'client_secret', 'cc', 'ccavi']: session[item] = data[item] except: + db.close() return redirect('/logout') #TODO: not good UX if 'cc' not in session: @@ -88,8 +96,10 @@ def home(): c.execute("UPDATE data SET avi = %s WHERE client_id = %s AND instance = %s", (session['avi'], session['client_id'], session['instance'])) session['last_avi_update'] = int(time.time()) db.commit() + db.close() return render_template("home.html", mabg="background-image:url('{}')".format(session['avi']), ccbg="background-image:url('{}')".format(session['ccavi'])) else: + db.close() return redirect(url_for('main')) @@ -138,6 +148,7 @@ def internal_auth_a(): #TODO: prevent these endpoints from being spammed somehow @app.route('/internal/auth_b') def internal_auth_b(): #write details to DB + db, c, dc = db_reconnect() client = Mastodon(client_id=session['client_id'], client_secret=session['client_secret'], api_base_url=session['instance']) session['secret'] = client.log_in(code = request.args.get('code'), scopes=scopes, redirect_uri='{}/internal/auth_b'.format(cfg['base_uri'])) acct_info = client.account_verify_credentials() @@ -149,12 +160,15 @@ def internal_auth_b(): #user already has an account with CG #update the user's info to use the new info we just got, then redirect them to the login page c.execute("UPDATE data SET client_id = %s, client_secret = %s, secret = %s, avi = %s WHERE username = %s AND instance = %s", (session['client_id'], session['client_secret'], session['secret'], session['avi'], session['username'], session['instance'])) + db.close() return redirect(url_for('log_in')) else: + db.close() return redirect(url_for('create_password')) @app.route('/internal/do_login', methods = ['POST']) def do_login(): + db, c, dc = db_reconnect() pw_in = request.form['pw'] pw_hashed = hashlib.sha256(pw_in.encode('utf-8')).digest() acct = request.form['acct'] @@ -162,6 +176,7 @@ def do_login(): session['instance'] = "https://{}".format(re.search("@([^@]+)$", acct).group(1)) dc.execute("SELECT * FROM data WHERE username = %s AND instance = %s", (session['username'], session['instance'])) data = dc.fetchone() + db.close() if bcrypt.checkpw(pw_hashed, data['password'].encode('utf-8')): #password is correct, log the user in for item in ['username', 'instance', 'avi', 'secret', 'client_id', 'client_secret', 'cc', 'ccavi']: @@ -173,7 +188,9 @@ def do_login(): @app.route('/create_password') def create_password(): + db, c, dc = db_reconnect() c.execute("SELECT COUNT(*) FROM data WHERE username = %s AND instance = %s", (session['username'], session['instance'])) + db.close() if c.fetchone()[0] == 0: return render_template("create_password.html", bg = "background-image:url('{}')".format(session['avi'])) else: @@ -182,13 +199,16 @@ def create_password(): @app.route('/internal/create_account', methods=['POST']) def create_account(): + db, c, dc = db_reconnect() pw_in = request.form['pw'] if len(pw_in) < 6 or pw_in == 'password': #TODO: this is a pretty crappy check + db.close() return redirect('/create_password?invalid') pw_hashed = hashlib.sha256(pw_in.encode('utf-8')).digest() pw = bcrypt.hashpw(pw_hashed, bcrypt.gensalt(15)) c.execute("INSERT INTO data (username, instance, avi, password, secret, client_id, client_secret) VALUES (%s, %s, %s, %s, %s, %s, %s)", (session['username'], session['instance'], session['avi'], pw, session['secret'], session['client_id'], session['client_secret'])) db.commit() + db.close() return redirect(url_for('home')) #cc connection @@ -242,8 +262,10 @@ def ccc_c(): return redirect('/cc_connect/code?invalid') for item in ['cc', 'ccavi']: session[item] = session['cctemp'][item] + db, c, dc = db_reconnect() c.execute("UPDATE data SET cc = %s, ccavi = %s, latest_post = %s WHERE username = %s AND instance = %s", (session['cc'], session['ccavi'], session['cctemp']['latest_post'], session['username'], session['instance'])) db.commit() + db.close() del session['cctemp'] return redirect('/cc_connect/complete')