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-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-06 11:57:47 +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, appid TEXT NOT NULL, appsecret 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-06 09:11:03 +00:00
session [ ' instance_url ' ] = request . args . get ( ' url ' , default = ' mastodon.social ' , type = str )
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-06 10:30:48 +00:00
scopes = [ " write:statuses " , " read:accounts " ] ,
2018-11-06 09:11:03 +00:00
website = cfg [ ' website ' ] ,
redirect_uris = [ ' https://cg.lynnesbian.space/internal/auth_b ' ]
2018-11-04 23:17:28 +00:00
)
2018-11-06 09:11:03 +00:00
params = {
" client_id " : session [ ' client_id ' ] ,
" client_secret " : session [ ' client_secret ' ] ,
2018-11-06 10:30:48 +00:00
" scope " : " write:statuses+read:accounts " ,
2018-11-06 09:11:03 +00:00
" redirect_uri " : " https://cg.lynnesbian.space/internal/auth_b " ,
" response_type " : " code " ,
}
2018-11-06 10:30:48 +00:00
2018-11-06 09:11:03 +00:00
url = " {} /oauth/authorize? {} " . format ( session [ ' instance_url ' ] , urllib . parse . urlencode ( params ) )
2018-11-04 23:17:28 +00:00
return url
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 ( ) :
session [ ' secret ' ] = request . args . get ( ' code ' )
#write details to DB
2018-11-06 10:30:48 +00:00
client = Mastodon ( access_token = session [ ' secret ' ] , api_base_url = session [ ' instance_url ' ] )
session [ ' username ' ] = client . account_verify_credentials ( ) [ ' username ' ]
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 ) )
c . execute ( " INSERT INTO data (username, instance, password, secret, appid, appsecret) 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 ( )