Add Gravatar-style avatar endpoint, rename user-based requests to /avatar/user/<uid>

pull/6/head
radex 2023-10-23 19:48:00 +02:00
parent 0ae77291cc
commit 6f51489194
2 changed files with 65 additions and 1 deletions

View File

@ -11,6 +11,7 @@ import time
import io
import logging
import random
import hashlib
from PIL import Image, ImageDraw
import flask
@ -234,6 +235,68 @@ class AvatarCache:
cache = AvatarCache()
@bp.route('/avatar/<uid>', methods=['GET'])
def hash_for_uid(uid):
# NOTE: Gravatar documentation says to use SHA256, but everyone passes MD5 instead
email = f'{uid}@hackerspace.pl'.strip().lower()
hasher = hashlib.md5()
hasher.update(email.encode())
return hasher.hexdigest()
def get_all_user_uids(conn):
all_uids = []
results = conn.search_s(config.ldap_people, ldap.SCOPE_SUBTREE, 'uid=*', attrlist=['uid'])
for user, attrs in results:
uid = attrs['uid'][0].decode()
all_uids.append(uid)
return all_uids
class HashCache:
# email hash -> uid mapping
entries: dict[str, str] = {}
# deadline when this cache expires
deadline: float = 0
def get(self, email_hash: str) -> str:
self.rebuild_if_needed()
return self.entries.get(email_hash, 'default')
def reset(self):
self.entries = {}
self.deadline = 0
def rebuild_if_needed(self):
now = time.time()
if now > self.deadline:
self.rebuild()
def rebuild(self):
log.info("Rebuilding email hash cache")
conn = context.get_admin_connection()
users = get_all_user_uids(conn)
self.deadline = time.time() + config.avatar_cache_timeout
self.entries = { hash_for_uid(uid): uid for uid in users }
hash_cache = HashCache()
def sanitize_email_hash(hash: str):
"""
lowercases, removes file extension (probably)
"""
hash = hash.lower()
if hash.endswith('.png') or hash.endswith('.jpg'):
hash = hash[:-4]
return hash
@bp.route('/avatar/<email_hash>', methods=['GET'])
def gravatar_serve(email_hash):
"""
Serves avatar in a Gravatar-compatible(ish) way, i.e. by email hash, not user name.
"""
uid = hash_cache.get(sanitize_email_hash(email_hash))
return cache.get(uid)
@bp.route('/avatar/user/<uid>', methods=['GET'])
def avatar_serve(uid):
return cache.get(uid)

View File

@ -52,5 +52,6 @@ def refresh_profile(dn=None):
# bust avatar cache
if user_uid:
avatar.cache.reset_user(user_uid)
avatar.hash_cache.reset()
return profile