feat: Add avatar route
All checks were successful
Build Docker / Build Docker (push) Successful in 1m7s

This commit is contained in:
Nathan Woodburn 2024-06-13 16:53:25 +10:00
parent 2b7c586862
commit 0bc07e491e
Signed by: nathanwoodburn
GPG Key ID: 203B000478AD0EF1
3 changed files with 59 additions and 26 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
__pycache__/ __pycache__/
instance/ instance/
website/avatars/

View File

@ -1,4 +1,6 @@
Flask Flask
Flask-SQLAlchemy Flask-SQLAlchemy
Authlib Authlib
requests requests
dnspython
requests-doh

View File

@ -7,10 +7,18 @@ from authlib.integrations.flask_oauth2 import current_token
from authlib.oauth2 import OAuth2Error from authlib.oauth2 import OAuth2Error
from .models import db, User, OAuth2Client from .models import db, User, OAuth2Client
from .oauth2 import authorization, require_oauth from .oauth2 import authorization, require_oauth
import os
import requests
import dns.message
import dns.query
import dns.rdatatype
from requests_doh import DNSOverHTTPSSession, add_dns_provider
bp = Blueprint("home", __name__) bp = Blueprint("home", __name__)
if not os.path.exists("website/avatars"):
os.makedirs("website/avatars")
def current_user(): def current_user():
if "id" in session: if "id" in session:
@ -148,7 +156,6 @@ def revoke_token():
@require_oauth(["profile", "openid"]) @require_oauth(["profile", "openid"])
def api_me(): def api_me():
user = current_token.user user = current_token.user
print(user.id, user.username, flush=True)
userInfo = { userInfo = {
"id": user.id, "id": user.id,
"uid": user.id, "uid": user.id,
@ -162,33 +169,10 @@ def api_me():
"nickname": user.username, "nickname": user.username,
"preferred_username": user.username, "preferred_username": user.username,
"profile": f"https://login.hns.au/u/{user.username}", "profile": f"https://login.hns.au/u/{user.username}",
"picture": f"https://login.hns.au/u/{user.username}/avatar", "picture": f"https://login.hns.au/u/{user.username}/avatar.png",
"website": f"https://{user.username}", "website": f"https://{user.username}",
"email_verified": True "email_verified": True
} }
print(userInfo, flush=True)
# a = [
# "sub",
# "name",
# "given_name",
# "family_name",
# "middle_name",
# "nickname",
# "preferred_username",
# "profile",
# "picture",
# "website",
# "email",
# "email_verified",
# "gender",
# "birthdate",
# "zoneinfo",
# "locale",
# "phone_number",
# "phone_number_verified",
# "address",
# "updated_at",
# ]
return jsonify(userInfo) return jsonify(userInfo)
@ -214,6 +198,51 @@ def autodiscovery():
return jsonify(discovery) return jsonify(discovery)
@bp.route("/u/<username>")
def profile(username):
user = User.query.filter_by(username=username).first()
return jsonify({"name": user.username, "id": user.id})
@bp.route("/u/<username>/avatar.png")
def avatar(username):
# Check if file exists
if os.path.exists(f"website/avatars/{username}.png"):
return send_from_directory("avatars", f"{username}.png", mimetype="image/png")
# If not, download from HNS info
query = dns.message.make_query(username, dns.rdatatype.TXT)
dns_request = query.to_wire()
# Send the DNS query over HTTPS
response = requests.post('https://hnsdoh.com/dns-query', data=dns_request, headers={'Content-Type': 'application/dns-message'})
# Parse the DNS response
dns_response = dns.message.from_wire(response.content)
# Loop over TXT records and look for profile avatar
avatar_url=""
for record in dns_response.answer:
if record.rdtype == dns.rdatatype.TXT:
for txt in record:
txt_value = txt.to_text().strip('"')
if txt_value.startswith("profile avatar="):
avatar_url = txt_value.split("profile avatar=")[1]
break
if avatar_url != "":
# Download the avatar using DNS-over-HTTPS
add_dns_provider("hns", "https://hnsdoh.com/dns-query")
session = DNSOverHTTPSSession(provider="hns")
response = session.get(avatar_url)
with open(f"website/avatars/{username}.png", "wb") as f:
f.write(response.content)
return send_from_directory("avatars", f"{username}.png", mimetype="image/png")
return send_from_directory("templates", "favicon.png", mimetype="image/png")
@bp.route("/favicon.png") @bp.route("/favicon.png")
def favicon(): def favicon():