forked from forks/microblog.pub
IndieAuth tweaks
This commit is contained in:
parent
d104290675
commit
fb6a08426f
1 changed files with 46 additions and 20 deletions
66
app.py
66
app.py
|
@ -19,7 +19,6 @@ from urllib.parse import urlparse
|
||||||
|
|
||||||
import bleach
|
import bleach
|
||||||
import mf2py
|
import mf2py
|
||||||
import pymongo
|
|
||||||
import requests
|
import requests
|
||||||
import timeago
|
import timeago
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
|
@ -2147,18 +2146,21 @@ def indieauth_flow():
|
||||||
state=request.form.get("state"),
|
state=request.form.get("state"),
|
||||||
redirect_uri=request.form.get("redirect_uri"),
|
redirect_uri=request.form.get("redirect_uri"),
|
||||||
response_type=request.form.get("response_type"),
|
response_type=request.form.get("response_type"),
|
||||||
|
ts=datetime.now().timestamp(),
|
||||||
|
code=binascii.hexlify(os.urandom(8)).decode("utf-8"),
|
||||||
|
verified=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
code = binascii.hexlify(os.urandom(8)).decode("utf-8")
|
# XXX(tsileo): a whitelist for me values?
|
||||||
auth.update(code=code, verified=False)
|
|
||||||
print(auth)
|
# TODO(tsileo): redirect_uri checks
|
||||||
if not auth["redirect_uri"]:
|
if not auth["redirect_uri"]:
|
||||||
abort(500)
|
abort(400)
|
||||||
|
|
||||||
DB.indieauth.insert_one(auth)
|
DB.indieauth.insert_one(auth)
|
||||||
|
|
||||||
# FIXME(tsileo): fetch client ID and validate redirect_uri
|
# FIXME(tsileo): fetch client ID and validate redirect_uri
|
||||||
red = f'{auth["redirect_uri"]}?code={code}&state={auth["state"]}&me={auth["me"]}'
|
red = f'{auth["redirect_uri"]}?code={auth["code"]}&state={auth["state"]}&me={auth["me"]}'
|
||||||
return redirect(red)
|
return redirect(red)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2198,13 +2200,17 @@ def indieauth_endpoint():
|
||||||
"code": code,
|
"code": code,
|
||||||
"redirect_uri": redirect_uri,
|
"redirect_uri": redirect_uri,
|
||||||
"client_id": client_id,
|
"client_id": client_id,
|
||||||
}, # }, # , 'verified': False},
|
"verified": False,
|
||||||
{"$set": {"verified": True}},
|
},
|
||||||
sort=[("_id", pymongo.DESCENDING)],
|
{"$set": {"verified": True, "action": "login"}},
|
||||||
)
|
)
|
||||||
print(auth)
|
print(auth)
|
||||||
print(code, redirect_uri, client_id)
|
print(code, redirect_uri, client_id)
|
||||||
|
|
||||||
|
# Ensure the code is recent
|
||||||
|
if (datetime.now() - datetime.fromtimetamp(auth["ts"])) > timedelta(minutes=5):
|
||||||
|
abort(400)
|
||||||
|
|
||||||
if not auth:
|
if not auth:
|
||||||
abort(403)
|
abort(403)
|
||||||
return
|
return
|
||||||
|
@ -2212,36 +2218,54 @@ def indieauth_endpoint():
|
||||||
session["logged_in"] = True
|
session["logged_in"] = True
|
||||||
me = auth["me"]
|
me = auth["me"]
|
||||||
state = auth["state"]
|
state = auth["state"]
|
||||||
scope = auth["scope"].split()
|
scope = auth["scope"]
|
||||||
print("STATE", state)
|
print("STATE", state)
|
||||||
return build_auth_resp({"me": me, "state": state, "scope": scope})
|
return build_auth_resp({"me": me, "state": state, "scope": scope})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/token", methods=["GET", "POST"])
|
@app.route("/token", methods=["GET", "POST"])
|
||||||
def token_endpoint():
|
def token_endpoint():
|
||||||
|
# Generate a new token with the returned access code
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
code = request.form.get("code")
|
code = request.form.get("code")
|
||||||
me = request.form.get("me")
|
me = request.form.get("me")
|
||||||
redirect_uri = request.form.get("redirect_uri")
|
redirect_uri = request.form.get("redirect_uri")
|
||||||
client_id = request.form.get("client_id")
|
client_id = request.form.get("client_id")
|
||||||
|
|
||||||
auth = DB.indieauth.find_one(
|
auth = DB.indieauth.find_one_and_update(
|
||||||
{
|
{
|
||||||
"code": code,
|
"code": code,
|
||||||
"me": me,
|
"me": me,
|
||||||
"redirect_uri": redirect_uri,
|
"redirect_uri": redirect_uri,
|
||||||
"client_id": client_id,
|
"client_id": client_id,
|
||||||
}
|
"verified": False,
|
||||||
|
},
|
||||||
|
{"$set": {"verified": True, "action": "token"}},
|
||||||
)
|
)
|
||||||
if not auth:
|
if not auth:
|
||||||
abort(403)
|
abort(403)
|
||||||
scope = auth["scope"].split()
|
|
||||||
payload = dict(
|
|
||||||
me=me, client_id=client_id, scope=scope, ts=datetime.now().timestamp()
|
|
||||||
)
|
|
||||||
token = JWT.dumps(payload).decode("utf-8")
|
|
||||||
|
|
||||||
return build_auth_resp({"me": me, "scope": scope, "access_token": token})
|
now = datetime.now()
|
||||||
|
# Ensure the code is recent
|
||||||
|
if (now - datetime.fromtimetamp(auth["ts"])) > timedelta(minutes=5):
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
scope = auth["scope"].split()
|
||||||
|
payload = dict(me=me, client_id=client_id, scope=scope, ts=now.timestamp())
|
||||||
|
token = JWT.dumps(payload).decode("utf-8")
|
||||||
|
DB.indieauth.update_one(
|
||||||
|
{"_id": auth["_id"]},
|
||||||
|
{
|
||||||
|
"$set": {
|
||||||
|
"token": token,
|
||||||
|
"token_expires": (now + timedelta(minutes=30)).timestamp(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return build_auth_resp(
|
||||||
|
{"me": me, "scope": auth["scope"], "access_token": token}
|
||||||
|
)
|
||||||
|
|
||||||
# Token verification
|
# Token verification
|
||||||
token = request.headers.get("Authorization").replace("Bearer ", "")
|
token = request.headers.get("Authorization").replace("Bearer ", "")
|
||||||
|
@ -2250,12 +2274,14 @@ def token_endpoint():
|
||||||
except BadSignature:
|
except BadSignature:
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
# TODO(tsileo): handle expiration
|
# Check the token expritation (valid for 3 hours)
|
||||||
|
if (datetime.now() - datetime.fromtimetamp(payload["ts"])) > timedelta(minutes=180):
|
||||||
|
abort(401)
|
||||||
|
|
||||||
return build_auth_resp(
|
return build_auth_resp(
|
||||||
{
|
{
|
||||||
"me": payload["me"],
|
"me": payload["me"],
|
||||||
"scope": payload["scope"],
|
"scope": " ".join(payload["scope"]),
|
||||||
"client_id": payload["client_id"],
|
"client_id": payload["client_id"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue