2018-11-01 14:25:47 +00:00
#!/usr/bin/env python3
#Curious Greg - Curious Cat to Mastodon crossposter
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
2018-11-06 23:10:50 +00:00
import requests , sqlite3 , json , hashlib
2018-11-01 14:25:47 +00:00
from mastodon import Mastodon
2018-11-04 23:17:28 +00:00
from flask import Flask , render_template , request , session , redirect , url_for
2018-11-06 10:30:48 +00:00
import bcrypt
2018-11-06 09:11:03 +00:00
import urllib
2018-11-01 14:25:47 +00:00
2018-11-02 02:35:40 +00:00
cfg = json . load ( open ( " meta.json " ) )
2018-11-10 06:38:43 +00:00
scopes = [ " read:accounts " , " write:statuses " ]
2018-11-02 02:35:40 +00:00
2018-11-06 10:30:48 +00:00
db = sqlite3 . connect ( " database.db " ) #TODO: switch to mysql so concurrency is possible
2018-11-01 14:25:47 +00:00
c = db . cursor ( )
2018-11-10 06:38:43 +00:00
c . execute ( " CREATE TABLE IF NOT EXISTS `data` (username TEXT NOT NULL, instance TEXT NOT NULL, password TEXT NOT NULL, avi TEXT NOT NULL, secret TEXT NOT NULL, client_id TEXT NOT NULL, client_secret TEXT NOT NULL, cc TEXT, latest_post TEXT, latest_timestamp TEXT, time_between_checks INT) " )
2018-11-01 15:17:02 +00:00
2018-11-02 02:59:29 +00:00
app = Flask ( cfg [ ' name ' ] )
2018-11-02 03:13:08 +00:00
app . secret_key = cfg [ ' flask_key ' ]
2018-11-02 02:59:29 +00:00
2018-11-02 03:13:08 +00:00
@app.route ( ' / ' )
def main ( ) :
2018-11-04 23:17:28 +00:00
if ' acct ' not in session :
return render_template ( " landing_page.html " )
else :
return redirect ( url_for ( ' home ' ) )
@app.route ( ' /home ' )
def home ( ) :
2018-11-06 09:11:03 +00:00
if ' acct ' in session :
acct = session [ ' acct ' ]
return render_template ( " home.html " , acct = acct )
else :
return redirect ( url_for ( ' main ' ) )
2018-11-02 02:59:29 +00:00
2018-11-06 11:22:10 +00:00
@app.route ( ' /debug ' ) #TODO: remove this before making the site live ;p
def print_debug_info ( ) :
return json . dumps ( session . _get_current_object ( ) )
@app.route ( ' /login ' )
def log_in ( ) :
if ' acct ' in session :
#user is probably already logged in. if they aren't, home() will handle things and redirect them back here
return redirect ( url_for ( ' home ' ) )
return render_template ( " login.html " )
# return(json.dumps(client_info))
#internal stuff
2018-11-02 02:59:29 +00:00
@app.route ( ' /internal/auth_a ' )
2018-11-06 11:57:47 +00:00
def internal_auth_a ( ) : #TODO: prevent these endpoints from being spammed somehow
2018-11-04 11:36:25 +00:00
2018-11-10 06:38:43 +00:00
session [ ' instance_url ' ] = request . args . get ( ' instance ' , default = ' mastodon.social ' , type = str )
2018-11-06 09:11:03 +00:00
if not session [ ' instance_url ' ] . startswith ( " https:// " ) :
session [ ' instance_url ' ] = " https:// {} " . format ( session [ ' instance_url ' ] )
session [ ' client_id ' ] , session [ ' client_secret ' ] = Mastodon . create_app ( cfg [ ' name ' ] ,
api_base_url = session [ ' instance_url ' ] ,
2018-11-10 06:38:43 +00:00
scopes = scopes ,
2018-11-06 09:11:03 +00:00
website = cfg [ ' website ' ] ,
2018-11-10 06:38:43 +00:00
redirect_uris = [ ' https://cg.lynnesbian.space/internal/auth_b ' , ' http://localhost:5000/internal/auth_b ' ]
2018-11-04 23:17:28 +00:00
)
2018-11-10 06:38:43 +00:00
client = Mastodon ( client_id = session [ ' client_id ' ] , client_secret = session [ ' client_secret ' ] , api_base_url = session [ ' instance_url ' ] )
url = client . auth_request_url ( client_id = session [ ' client_id ' ] , redirect_uris = ' http://localhost:5000/internal/auth_b ' , scopes = scopes )
return redirect ( url , code = 307 )
2018-11-02 07:52:33 +00:00
2018-11-06 09:11:03 +00:00
@app.route ( ' /internal/auth_b ' )
def internal_auth_b ( ) :
#write details to DB
2018-11-10 06:38:43 +00:00
client = Mastodon ( client_id = session [ ' client_id ' ] , client_secret = session [ ' client_secret ' ] , api_base_url = session [ ' instance_url ' ] )
session [ ' secret ' ] = client . log_in ( code = request . args . get ( ' code ' ) , scopes = scopes , redirect_uri = ' http://localhost:5000/internal/auth_b ' )
acct_info = client . account_verify_credentials ( )
session [ ' username ' ] = acct_info [ ' username ' ]
session [ ' avi ' ] = acct_info [ ' avatar ' ]
2018-11-06 10:30:48 +00:00
session [ ' acct ' ] = " @ {} @ {} " . format ( session [ ' username ' ] , session [ ' instance_url ' ] . replace ( " https:// " , " " ) )
if c . execute ( " SELECT COUNT(*) FROM data WHERE username LIKE ? AND instance LIKE ? " , ( session [ ' username ' ] , session [ ' instance_url ' ] ) ) . fetchone ( ) [ 0 ] > 0 :
#user already has an account with CG
return redirect ( url_for ( ' log_in ' ) )
2018-11-06 11:57:47 +00:00
else :
return redirect ( url_for ( ' home ' ) )
2018-11-06 09:11:03 +00:00
2018-11-06 11:22:10 +00:00
@app.route ( ' /internal/do_login ' )
def do_login ( ) :
pass
2018-11-06 10:30:48 +00:00
2018-11-06 11:22:10 +00:00
@app.route ( ' /create_password ' )
def create_password ( ) :
2018-11-06 11:57:47 +00:00
return render_template ( " create_password.html " )
2018-11-06 23:10:50 +00:00
@app.route ( ' /internal/create_account ' , methods = [ ' POST ' ] )
2018-11-06 11:57:47 +00:00
def create_account ( ) :
2018-11-06 23:10:50 +00:00
pw = bcrypt . hashpw ( request . form [ ' pw ' ] , bcrypt . gensalt ( 15 ) )
2018-11-10 06:38:43 +00:00
c . execute ( " INSERT INTO data (username, instance, avi, password, secret, client_id, client_secret) VALUES (?, ?, ?, ?, ?) " , ( session [ ' username ' ] , pw , session [ ' instance_url ' ] , session [ ' secret ' ] , session [ ' client_id ' ] , session [ ' client_secret ' ] ) )
2018-11-06 11:57:47 +00:00
db . commit ( )