now works.
This commit is contained in:
parent
d30292d141
commit
762c918223
94
auth.py
94
auth.py
|
@ -4,19 +4,66 @@ from markupsafe import escape
|
|||
from mastodon import Mastodon
|
||||
from email.headerregistry import Address
|
||||
import jwt
|
||||
import shelve
|
||||
from gevent.pywsgi import WSGIServer
|
||||
import os
|
||||
import sqlite3
|
||||
import zulip
|
||||
import random
|
||||
import string
|
||||
|
||||
SECRET = os.environ["SECRET"]
|
||||
ZULIP = f"https://{os.environ['ZULIP']}/accounts/login/jwt/"
|
||||
REDIRECT = f"https://{os.environ['ZULIP']}/callback"
|
||||
SHELVE_LOCATION = os.environ.get("DB_DIR", "/var/lib/fedi-zulip")
|
||||
PORT = int(os.environ.get("PORT", "5000"))
|
||||
REDIRECT = f"https://{os.environ['ZULIP']}/fedi-auth/callback"
|
||||
DB = os.environ.get("DB", "/var/lib/fedi-zulip/db/applications")
|
||||
|
||||
print(f"""
|
||||
Zulip is: {os.environ['ZULIP']}
|
||||
DB location is: {DB}
|
||||
""")
|
||||
|
||||
con = sqlite3.connect(DB)
|
||||
cur = con.cursor()
|
||||
|
||||
zulip_client = zulip.Client()
|
||||
|
||||
def get_zulip_user(handle):
|
||||
zulip_client.call_endpoint(
|
||||
url=f"/users/{handle}",
|
||||
method="GET"
|
||||
)
|
||||
|
||||
def create_zulip_user(handle):
|
||||
password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=40))
|
||||
return zulip_client.create_user({
|
||||
"email": handle,
|
||||
"password": password,
|
||||
"full_name": handle.split('@')[0]
|
||||
})
|
||||
|
||||
def get_or_create_zulip_user(handle):
|
||||
user = get_zulip_user(handle)
|
||||
if user is None:
|
||||
print(f"User: {handle} created.")
|
||||
user = create_zulip_user(handle)
|
||||
else:
|
||||
print(f"User: {handle} already exists.")
|
||||
|
||||
return user
|
||||
|
||||
|
||||
cur.execute("CREATE TABLE IF NOT EXISTS applications(instance TEXT PRIMARY KEY, client TEXT, secret TEXT, disabled BOOLEAN DEFAULT FALSE)")
|
||||
|
||||
def get_application(instance):
|
||||
res = cur.execute("SELECT client, secret FROM applications WHERE instance = ?", [instance])
|
||||
return res.fetchone();
|
||||
|
||||
def set_application(instance, client, secret):
|
||||
res = cur.execute("INSERT INTO applications(instance, client, secret) values (?, ?, ?)", (instance, client, secret));
|
||||
con.commit();
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.get("/")
|
||||
@app.get("/fedi-auth/")
|
||||
def index():
|
||||
return f"""
|
||||
<!DOCTYPE html>
|
||||
|
@ -27,7 +74,7 @@ def index():
|
|||
You can use this page to login to {os.environ['ZULIP']} using your
|
||||
Pleroma, Akkoma or Mastodon handle. Format is <code>nickname@server</code>.
|
||||
</p>
|
||||
<form action="/login" method="post">
|
||||
<form action="/fedi-auth/login" method="post">
|
||||
<label for="nickname">Fediverse handle</label>
|
||||
<br>
|
||||
<input type="email" id="nickname" name="nickname">
|
||||
|
@ -38,27 +85,31 @@ def index():
|
|||
"""
|
||||
|
||||
|
||||
@app.post("/login")
|
||||
@app.post("/fedi-auth/login")
|
||||
def login():
|
||||
print("Login POST", flush=True)
|
||||
instance = Address(addr_spec=request.form["nickname"]).domain
|
||||
print(f"Instance is: {instance}.", flush=True)
|
||||
try:
|
||||
with shelve.open(SHELVE_LOCATION) as apps:
|
||||
app = apps.get(instance)
|
||||
app = get_application(instance)
|
||||
if app == None:
|
||||
print(f"There is no OAuth application for {instance} so creating one.", flush=True)
|
||||
(client, secret) = Mastodon.create_app(
|
||||
"zulip",
|
||||
scopes=["read"],
|
||||
redirect_uris=REDIRECT,
|
||||
api_base_url=f"https://{instance}",
|
||||
)
|
||||
apps[instance] = (client, secret)
|
||||
app = (client, secret)
|
||||
set_application(instance, client, secret)
|
||||
|
||||
(client, secret) = apps[instance]
|
||||
(client, secret) = app
|
||||
masto = Mastodon(
|
||||
client_id=client,
|
||||
client_secret=secret,
|
||||
api_base_url=f"https://{instance}",
|
||||
)
|
||||
print(f"Getting login URI for {instance}.", flush=True)
|
||||
oauth = Mastodon.auth_request_url(
|
||||
masto,
|
||||
scopes=["read"],
|
||||
|
@ -66,20 +117,21 @@ def login():
|
|||
redirect_uris=REDIRECT,
|
||||
state=instance,
|
||||
)
|
||||
print(f"Sending user to: {REDIRECT}", flush=True)
|
||||
return redirect(oauth)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return Response("fail", status=400)
|
||||
|
||||
|
||||
@app.get("/callback")
|
||||
@app.get("/fedi-auth/callback")
|
||||
def callback():
|
||||
oauth = request.args.get("code")
|
||||
instance = request.args.get("state")
|
||||
print(f"oauth: {oauth is not None} instance: {instance is not None}")
|
||||
if oauth != None and instance != None:
|
||||
try:
|
||||
with shelve.open(SHELVE_LOCATION) as apps:
|
||||
app = apps.get(instance)
|
||||
app = get_application(instance)
|
||||
if app != None:
|
||||
masto = Mastodon(
|
||||
client_id=app[0],
|
||||
|
@ -88,8 +140,13 @@ def callback():
|
|||
)
|
||||
Mastodon.log_in(masto, code=oauth, scopes=["read"])
|
||||
creds = Mastodon.account_verify_credentials(masto)
|
||||
handle = f"{creds.acct}@{instance}"
|
||||
|
||||
zulip_user = get_or_create_zulip_user(handle)
|
||||
print(zulip_user)
|
||||
|
||||
token = jwt.encode(
|
||||
{"email": f"{creds.acct}@{instance}"},
|
||||
{"email": handle},
|
||||
SECRET,
|
||||
algorithm="HS256",
|
||||
)
|
||||
|
@ -107,9 +164,8 @@ def callback():
|
|||
</body>
|
||||
</html>
|
||||
"""
|
||||
except:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
print("Some field wasn't set.")
|
||||
return Response("fail", status=400)
|
||||
|
||||
http_server = WSGIServer(("127.0.0.1", PORT), app)
|
||||
http_server.serve_forever()
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
flask
|
||||
markupsafe
|
||||
mastodon
|
||||
mastodon.py
|
||||
pyjwt
|
||||
gevent
|
||||
gunicorn
|
||||
zulip
|
||||
|
|
Loading…
Reference in New Issue