You've already forked snikket-web-portal
Improve avatar route handler
- Fix etag attaching (add_etag is actually a coroutine which hashes the data payload) - Add expires header (with now + 1800s default) so that we don’t get hit with an avatar request on each load -- also helps with page responsiveness. - Proper handling for HEAD requests. - CSP to prevent funny SVG attacks.
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
import base64
|
import base64
|
||||||
import binascii
|
import binascii
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import quart.flask_patch
|
import quart.flask_patch
|
||||||
|
|
||||||
from quart import (
|
from quart import (
|
||||||
Quart, session, request, render_template, redirect, url_for, Response
|
Quart, session, request, render_template, redirect, url_for, Response,
|
||||||
|
current_app,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import colour
|
from . import colour
|
||||||
@@ -66,20 +69,33 @@ async def avatar(from_, code):
|
|||||||
bin_hash = binascii.a2b_hex(info["sha1"])
|
bin_hash = binascii.a2b_hex(info["sha1"])
|
||||||
new_etag = base64.urlsafe_b64encode(bin_hash).decode("ascii").rstrip("=")
|
new_etag = base64.urlsafe_b64encode(bin_hash).decode("ascii").rstrip("=")
|
||||||
|
|
||||||
headers = {
|
cache_ttl = timedelta(seconds=current_app.config.get(
|
||||||
"ETag": new_etag,
|
"AVATAR_CACHE_TTL",
|
||||||
}
|
300,
|
||||||
|
))
|
||||||
|
|
||||||
if etag is not None:
|
response = Response(None, mimetype=info["type"])
|
||||||
if new_etag == etag:
|
response.headers["etag"] = new_etag
|
||||||
return Response(
|
# XXX: It seems to me that quart expects localtime(?!) in this field...
|
||||||
[],
|
response.expires = datetime.now() + cache_ttl
|
||||||
304,
|
response.headers["Content-Security-Policy"] = \
|
||||||
content_type=info["type"], headers=headers
|
"frame-ancestors 'none'; default-src 'none'; style-src 'unsafe-inline'"
|
||||||
)
|
|
||||||
|
if etag is not None and new_etag == etag:
|
||||||
|
response.status_code = 304
|
||||||
|
response.set_data("")
|
||||||
|
return response
|
||||||
|
|
||||||
data = await client.get_avatar_data(address, info["sha1"])
|
data = await client.get_avatar_data(address, info["sha1"])
|
||||||
return Response(data, content_type=info["type"], headers=headers)
|
response.status_code = 200
|
||||||
|
|
||||||
|
if request.method == "HEAD":
|
||||||
|
response.content_length = len(data)
|
||||||
|
response.set_data("")
|
||||||
|
return response
|
||||||
|
|
||||||
|
response.set_data(data)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
|
|||||||
Reference in New Issue
Block a user