From 607caa1a2db574a46fcd97d7e4ceeabc99a77e1a Mon Sep 17 00:00:00 2001 From: corubba Date: Fri, 27 May 2022 13:01:46 +0200 Subject: [PATCH] Rework user image handling Moved all the logic out of the template into a separate endpoint. This makes it easy to extend to also support images from different sources like LDAP/SAML/OIDC. Session-based caching is hard to do, so to allow time-based caching in the browser, the url needs to be unique for every user by using a query parameter. Replaced the default/fallback user image with a new one. It is based on the old one, but does not need css to be visible. And removed said css. Gravatar has now its own setting named `gravatar_enabled`, which is disabled by default. --- powerdnsadmin/__init__.py | 2 - powerdnsadmin/lib/utils.py | 13 ------ powerdnsadmin/models/setting.py | 3 +- powerdnsadmin/routes/admin.py | 47 +++++++++++++++------ powerdnsadmin/routes/user.py | 37 +++++++++++++++- powerdnsadmin/static/custom/css/custom.css | 9 ---- powerdnsadmin/static/img/gravatar.png | Bin 26693 -> 0 bytes powerdnsadmin/static/img/user_image.png | Bin 0 -> 2718 bytes powerdnsadmin/templates/base.html | 12 ++---- 9 files changed, 75 insertions(+), 48 deletions(-) delete mode 100644 powerdnsadmin/static/img/gravatar.png create mode 100644 powerdnsadmin/static/img/user_image.png diff --git a/powerdnsadmin/__init__.py b/powerdnsadmin/__init__.py index c70b273..3f68a58 100755 --- a/powerdnsadmin/__init__.py +++ b/powerdnsadmin/__init__.py @@ -100,8 +100,6 @@ def create_app(config=None): app.jinja_env.filters['display_record_name'] = utils.display_record_name app.jinja_env.filters['display_master_name'] = utils.display_master_name app.jinja_env.filters['display_second_to_time'] = utils.display_time - app.jinja_env.filters[ - 'email_to_gravatar_url'] = utils.email_to_gravatar_url app.jinja_env.filters[ 'display_setting_state'] = utils.display_setting_state app.jinja_env.filters['pretty_domain_name'] = utils.pretty_domain_name diff --git a/powerdnsadmin/lib/utils.py b/powerdnsadmin/lib/utils.py index 9e7cf20..4ef5759 100644 --- a/powerdnsadmin/lib/utils.py +++ b/powerdnsadmin/lib/utils.py @@ -2,14 +2,12 @@ import logging import re import json import requests -import hashlib import ipaddress import idna from collections.abc import Iterable from distutils.version import StrictVersion from urllib.parse import urlparse -from datetime import datetime, timedelta def auth_from_url(url): @@ -186,17 +184,6 @@ def pdns_api_extended_uri(version): return "" -def email_to_gravatar_url(email="", size=100): - """ - AD doesn't necessarily have email - """ - if email is None: - email = "" - - hash_string = hashlib.md5(email.encode('utf-8')).hexdigest() - return "https://s.gravatar.com/avatar/{0}?s={1}".format(hash_string, size) - - def display_setting_state(value): if value == 1: return "ON" diff --git a/powerdnsadmin/models/setting.py b/powerdnsadmin/models/setting.py index 51e78e5..a4016bf 100644 --- a/powerdnsadmin/models/setting.py +++ b/powerdnsadmin/models/setting.py @@ -193,7 +193,8 @@ class Setting(db.Model): 'otp_force': False, 'max_history_records': 1000, 'deny_domain_override': False, - 'account_name_extra_chars': False + 'account_name_extra_chars': False, + 'gravatar_enabled': False, } def __init__(self, id=None, name=None, value=None): diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index c5f28d1..9474503 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -1259,20 +1259,41 @@ def history_table(): # ajax call data @login_required @operator_role_required def setting_basic(): - if request.method == 'GET': - settings = [ - 'maintenance', 'fullscreen_layout', 'record_helper', - 'login_ldap_first', 'default_record_table_size', - 'default_domain_table_size', 'auto_ptr', 'record_quick_edit', - 'pretty_ipv6_ptr', 'dnssec_admins_only', - 'allow_user_create_domain', 'allow_user_remove_domain', 'allow_user_view_history', 'bg_domain_updates', 'site_name', - 'session_timeout', 'warn_session_timeout', 'ttl_options', - 'pdns_api_timeout', 'verify_ssl_connections', 'verify_user_email', - 'delete_sso_accounts', 'otp_field_enabled', 'custom_css', 'enable_api_rr_history', 'max_history_records', 'otp_force', - 'deny_domain_override', 'enforce_api_ttl', 'account_name_extra_chars' - ] + settings = [ + 'account_name_extra_chars', + 'allow_user_create_domain', + 'allow_user_remove_domain', + 'allow_user_view_history', + 'auto_ptr', + 'bg_domain_updates', + 'custom_css', + 'default_domain_table_size', + 'default_record_table_size', + 'delete_sso_accounts', + 'deny_domain_override', + 'dnssec_admins_only', + 'enable_api_rr_history', + 'enforce_api_ttl', + 'fullscreen_layout', + 'gravatar_enabled', + 'login_ldap_first', + 'maintenance', + 'max_history_records', + 'otp_field_enabled', + 'otp_force', + 'pdns_api_timeout', + 'pretty_ipv6_ptr', + 'record_helper', + 'record_quick_edit', + 'session_timeout', + 'site_name', + 'ttl_options', + 'verify_ssl_connections', + 'verify_user_email', + 'warn_session_timeout', + ] - return render_template('admin_setting_basic.html', settings=settings) + return render_template('admin_setting_basic.html', settings=settings) @admin_bp.route('/setting/basic//edit', methods=['POST']) diff --git a/powerdnsadmin/routes/user.py b/powerdnsadmin/routes/user.py index f411c29..709156f 100644 --- a/powerdnsadmin/routes/user.py +++ b/powerdnsadmin/routes/user.py @@ -1,5 +1,8 @@ import datetime -from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, current_app +import hashlib + +from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, \ + current_app, after_this_request, abort from flask_login import current_user, login_required, login_manager from ..models.user import User, Anonymous @@ -96,4 +99,34 @@ def qrcode(): 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' - } \ No newline at end of file + } + + +@user_bp.route('/image', methods=['GET']) +@login_required +def image(): + """Returns the user profile image or avatar.""" + + @after_this_request + def add_cache_headers(response_): + """When the response is ok, add cache headers.""" + if 200 <= response_.status_code <= 399: + response_.cache_control.private = True + response_.cache_control.max_age = int(datetime.timedelta(days=1).total_seconds()) + return response_ + + # To prevent "cache poisoning", the username query parameter is required + if request.args.get('username', None) != current_user.username: + abort(400) + + setting = Setting() + + email = current_user.email + if email and setting.get('gravatar_enabled'): + hash_ = hashlib.md5(email.encode('utf-8')).hexdigest() + url = f'https://s.gravatar.com/avatar/{hash_}?s=100' + current_app.logger.debug('Redirect user image request to gravatar') + return redirect(url, 307) + + # Fallback to the local default image + return current_app.send_static_file('img/user_image.png') diff --git a/powerdnsadmin/static/custom/css/custom.css b/powerdnsadmin/static/custom/css/custom.css index f5dcb34..1cd3728 100644 --- a/powerdnsadmin/static/custom/css/custom.css +++ b/powerdnsadmin/static/custom/css/custom.css @@ -42,15 +42,6 @@ table td { background-position: center; } -.navbar-nav>.user-menu>.dropdown-menu>li.user-header>img.img-circle.offline { - filter: brightness(0); - border-color: black; -} - -.navbar-nav>.user-menu .user-image.offline { - filter: brightness(0); -} - .search-input { width: 100%; } \ No newline at end of file diff --git a/powerdnsadmin/static/img/gravatar.png b/powerdnsadmin/static/img/gravatar.png deleted file mode 100644 index 83602867a01f97bef0586e5ed18f6243c3ac1974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26693 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 =0zvg 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 Pc|iF5$k3A^=FGnV3?!(& literal 0 HcmV?d00001 diff --git a/powerdnsadmin/templates/base.html b/powerdnsadmin/templates/base.html index 92e3a1c..85b2f82 100644 --- a/powerdnsadmin/templates/base.html +++ b/powerdnsadmin/templates/base.html @@ -23,11 +23,7 @@ {% endblock %} - {% if OFFLINE_MODE %} - {% set gravatar_url = url_for('static', filename='img/gravatar.png') %} - {% elif current_user.email is defined %} - {% set gravatar_url = current_user.email|email_to_gravatar_url(size=80) %} - {% endif %} +{% set user_image_url = url_for('user.image', username=current_user.username) %}
{% block pageheader %}
@@ -51,14 +47,14 @@