From 9c00e48f0f370a968d28cda1e77fcfc1e585710a Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Fri, 23 Jul 2021 06:56:09 +0000 Subject: [PATCH 001/203] routes/index.py: Make package 'onelogin.saml2.utils' optional The onelogin package is not part of all saml packages for whatever reason (e.g. Debian) and not easily installable from pypi (requires CC toolchain). As the onelogin functionality is already guarded by whether SAML_ENABLED is set in other places (services/saml.py), also do so in routes/index.py. --- powerdnsadmin/routes/index.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py index f1ddb6b..636c270 100644 --- a/powerdnsadmin/routes/index.py +++ b/powerdnsadmin/routes/index.py @@ -6,7 +6,6 @@ import datetime import ipaddress from distutils.util import strtobool from yaml import Loader, load -from onelogin.saml2.utils import OneLogin_Saml2_Utils from flask import Blueprint, render_template, make_response, url_for, current_app, g, session, request, redirect, abort from flask_login import login_user, logout_user, login_required, current_user @@ -847,6 +846,7 @@ def dyndns_update(): def saml_login(): if not current_app.config.get('SAML_ENABLED'): abort(400) + from onelogin.saml2.utils import OneLogin_Saml2_Utils req = saml.prepare_flask_request(request) auth = saml.init_saml_auth(req) redirect_url = OneLogin_Saml2_Utils.get_self_url(req) + url_for( @@ -859,7 +859,7 @@ def saml_metadata(): if not current_app.config.get('SAML_ENABLED'): current_app.logger.error("SAML authentication is disabled.") abort(400) - + from onelogin.saml2.utils import OneLogin_Saml2_Utils req = saml.prepare_flask_request(request) auth = saml.init_saml_auth(req) settings = auth.get_settings() From 10dc2b0273a178bd2dfe2cf1bc12e3c5d0b02f33 Mon Sep 17 00:00:00 2001 From: RoeiGanor Date: Fri, 13 Aug 2021 20:03:06 +0300 Subject: [PATCH 002/203] bg_domain button for operators and higher --- powerdnsadmin/routes/dashboard.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/powerdnsadmin/routes/dashboard.py b/powerdnsadmin/routes/dashboard.py index 457c415..c953ec7 100644 --- a/powerdnsadmin/routes/dashboard.py +++ b/powerdnsadmin/routes/dashboard.py @@ -3,6 +3,7 @@ from flask import Blueprint, render_template, url_for, current_app, request, jso from flask_login import login_required, current_user, login_manager from sqlalchemy import not_ +from ..decorators import operator_role_required from ..lib.utils import customBoxes from ..models.user import User, Anonymous from ..models.account import Account @@ -150,6 +151,10 @@ def dashboard(): else: current_app.logger.info('Updating domains in background...') + show_bg_domain_button = BG_DOMAIN_UPDATE + if BG_DOMAIN_UPDATE and current_user.role.name not in ['Administrator', 'Operator']: + show_bg_domain_button = False + # Stats for dashboard domain_count = 0 history_number = 0 @@ -198,12 +203,13 @@ def dashboard(): history_number=history_number, uptime=uptime, histories=history, - show_bg_domain_button=BG_DOMAIN_UPDATE, + show_bg_domain_button=show_bg_domain_button, pdns_version=Setting().get('pdns_version')) @dashboard_bp.route('/domains-updater', methods=['GET', 'POST']) @login_required +@operator_role_required def domains_updater(): current_app.logger.debug('Update domains in background') d = Domain().update() From 282c630eb8f1b837a9a13080842d6d2980b8ea08 Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Wed, 20 Oct 2021 13:18:30 +0000 Subject: [PATCH 003/203] dyndns: Respond with HTTP header 'WWW-Authenticate' to unauthed requests The common procedure for HTTP Basic Auth is that a client does /not/ immediately send out credentials via an 'Authorization'-header, but to wait until the server tells the client to do so - which the server indicates via the 'WWW-Authenticate'-header. PowerDNS-Admin (and flask in general), though, abort the whole communication if no Authorization header was found in the initial request - resulting in '200 "badauth"'. While this might work for /some/ HTTP clients - which right away add an Authorization header crafted from provided credentials (via args or extracted from given URL), this is /not/ standard and /not/ common. Hence add the 'WWW-Authenticate'-header for every unauthenticated call checking for dyndns authorisation. Note, though, this changes the status code from 200 to 401 in this case, which - given the explanation why 200 was chosen in the first place - might cause side effects. --- powerdnsadmin/decorators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerdnsadmin/decorators.py b/powerdnsadmin/decorators.py index 5bf6c96..4ee9a5a 100644 --- a/powerdnsadmin/decorators.py +++ b/powerdnsadmin/decorators.py @@ -1,7 +1,7 @@ import base64 import binascii from functools import wraps -from flask import g, request, abort, current_app, render_template +from flask import g, request, abort, current_app, Response from flask_login import current_user from .models import User, ApiKey, Setting, Domain, Setting @@ -301,7 +301,7 @@ def dyndns_login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if current_user.is_authenticated is False: - return render_template('dyndns.html', response='badauth'), 200 + return Response(headers={'WWW-Authenticate': 'Basic'}, status=401) return f(*args, **kwargs) return decorated_function From 94a923a965f0740aeb4d44c4abde9bb8c530bfc7 Mon Sep 17 00:00:00 2001 From: Vasileios Markopoulos <83133031+vmarkop@users.noreply.github.com> Date: Fri, 17 Dec 2021 12:41:51 +0200 Subject: [PATCH 004/203] Add 'otp_force' basic setting (#1051) If the 'otp_force' and 'otp_field_enabled' basic settings are both enabled, automatically enable 2FA for the user after login or signup, if needed, by setting a new OTP secret. Redirect the user to a welcome page for scanning the QR code. Also show the secret key in ASCII form on the user profile page for easier copying into other applications. --- powerdnsadmin/assets.py | 1 + powerdnsadmin/models/setting.py | 1 + powerdnsadmin/models/user.py | 15 +++- powerdnsadmin/routes/admin.py | 3 +- powerdnsadmin/routes/index.py | 72 +++++++++++++----- powerdnsadmin/routes/user.py | 11 +-- powerdnsadmin/static/custom/js/custom.js | 12 ++- powerdnsadmin/templates/register_otp.html | 90 +++++++++++++++++++++++ powerdnsadmin/templates/user_profile.html | 12 ++- 9 files changed, 179 insertions(+), 38 deletions(-) create mode 100755 powerdnsadmin/templates/register_otp.html diff --git a/powerdnsadmin/assets.py b/powerdnsadmin/assets.py index dfe79ff..e7c6354 100644 --- a/powerdnsadmin/assets.py +++ b/powerdnsadmin/assets.py @@ -23,6 +23,7 @@ css_login = Bundle('node_modules/bootstrap/dist/css/bootstrap.css', js_login = Bundle('node_modules/jquery/dist/jquery.js', 'node_modules/bootstrap/dist/js/bootstrap.js', 'node_modules/icheck/icheck.js', + 'custom/js/custom.js', filters=(ConcatFilter, 'jsmin'), output='generated/login.js') diff --git a/powerdnsadmin/models/setting.py b/powerdnsadmin/models/setting.py index a46cfb6..33b8db5 100644 --- a/powerdnsadmin/models/setting.py +++ b/powerdnsadmin/models/setting.py @@ -189,6 +189,7 @@ class Setting(db.Model): 'ttl_options': '1 minute,5 minutes,30 minutes,60 minutes,24 hours', 'otp_field_enabled': True, 'custom_css': '', + 'otp_force': False, 'max_history_records': 1000 } diff --git a/powerdnsadmin/models/user.py b/powerdnsadmin/models/user.py index f5e3556..ca0561b 100644 --- a/powerdnsadmin/models/user.py +++ b/powerdnsadmin/models/user.py @@ -8,6 +8,9 @@ import ldap.filter from flask import current_app from flask_login import AnonymousUserMixin from sqlalchemy import orm +import qrcode as qrc +import qrcode.image.svg as qrc_svg +from io import BytesIO from .base import db from .role import Role @@ -633,6 +636,13 @@ class User(db.Model): for q in query: accounts.append(q[1]) return accounts + + def get_qrcode_value(self): + img = qrc.make(self.get_totp_uri(), + image_factory=qrc_svg.SvgPathImage) + stream = BytesIO() + img.save(stream) + return stream.getvalue() def read_entitlements(self, key): @@ -794,7 +804,4 @@ def getUserInfo(DomainsOrAccounts): current=[] for DomainOrAccount in DomainsOrAccounts: current.append(DomainOrAccount.name) - return current - - - + return current \ No newline at end of file diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index 17d84a6..5573502 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -1260,8 +1260,7 @@ def setting_basic(): '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' - + 'delete_sso_accounts', 'otp_field_enabled', 'custom_css', 'enable_api_rr_history', 'max_history_records', 'otp_force' ] return render_template('admin_setting_basic.html', settings=settings) diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py index ccdcd6b..316db2d 100644 --- a/powerdnsadmin/routes/index.py +++ b/powerdnsadmin/routes/index.py @@ -4,6 +4,7 @@ import json import traceback import datetime import ipaddress +import base64 from distutils.util import strtobool from yaml import Loader, load from onelogin.saml2.utils import OneLogin_Saml2_Utils @@ -167,10 +168,8 @@ def login(): return redirect(url_for('index.login')) session['user_id'] = user.id - login_user(user, remember=False) session['authentication_type'] = 'OAuth' - signin_history(user.username, 'Google OAuth', True) - return redirect(url_for('index.index')) + return authenticate_user(user, 'Google OAuth') if 'github_token' in session: me = json.loads(github.get('user').text) @@ -195,9 +194,7 @@ def login(): session['user_id'] = user.id session['authentication_type'] = 'OAuth' - login_user(user, remember=False) - signin_history(user.username, 'Github OAuth', True) - return redirect(url_for('index.index')) + return authenticate_user(user, 'Github OAuth') if 'azure_token' in session: azure_info = azure.get('me?$select=displayName,givenName,id,mail,surname,userPrincipalName').text @@ -366,10 +363,7 @@ def login(): history.add() current_app.logger.warning('group info: {} '.format(account_id)) - - login_user(user, remember=False) - signin_history(user.username, 'Azure OAuth', True) - return redirect(url_for('index.index')) + return authenticate_user(user, 'Azure OAuth') if 'oidc_token' in session: me = json.loads(oidc.get('userinfo').text) @@ -433,9 +427,7 @@ def login(): session['user_id'] = user.id session['authentication_type'] = 'OAuth' - login_user(user, remember=False) - signin_history(user.username, 'OIDC OAuth', True) - return redirect(url_for('index.index')) + return authenticate_user(user, 'OIDC OAuth') if request.method == 'GET': return render_template('login.html', saml_enabled=SAML_ENABLED) @@ -512,9 +504,7 @@ def login(): user.revoke_privilege(True) current_app.logger.warning('Procceding to revoke every privilige from ' + user.username + '.' ) - login_user(user, remember=remember_me) - signin_history(user.username, 'LOCAL', True) - return redirect(session.get('next', url_for('index.index'))) + return authenticate_user(user, 'LOCAL', remember_me) def checkForPDAEntries(Entitlements, urn_value): """ @@ -584,6 +574,23 @@ def get_azure_groups(uri): mygroups = [] return mygroups +# Handle user login, write history and, if set, handle showing the register_otp QR code. +# if Setting for OTP on first login is enabled, and OTP field is also enabled, +# but user isn't using it yet, enable OTP, get QR code and display it, logging the user out. +def authenticate_user(user, authenticator, remember=False): + login_user(user, remember=remember) + signin_history(user.username, authenticator, True) + if Setting().get('otp_force') and Setting().get('otp_field_enabled') and not user.otp_secret: + user.update_profile(enable_otp=True) + user_id = current_user.id + prepare_welcome_user(user_id) + return redirect(url_for('index.welcome')) + return redirect(url_for('index.login')) + +# Prepare user to enter /welcome screen, otherwise they won't have permission to do so +def prepare_welcome_user(user_id): + logout_user() + session['welcome_user_id'] = user_id @index_bp.route('/logout') def logout(): @@ -674,7 +681,12 @@ def register(): if result and result['status']: if Setting().get('verify_user_email'): send_account_verification(email) - return redirect(url_for('index.login')) + if Setting().get('otp_force') and Setting().get('otp_field_enabled'): + user.update_profile(enable_otp=True) + prepare_welcome_user(user.id) + return redirect(url_for('index.welcome')) + else: + return redirect(url_for('index.login')) else: return render_template('register.html', error=result['msg']) @@ -684,6 +696,28 @@ def register(): return render_template('errors/404.html'), 404 +# Show welcome page on first login if otp_force is enabled +@index_bp.route('/welcome', methods=['GET', 'POST']) +def welcome(): + if 'welcome_user_id' not in session: + return redirect(url_for('index.index')) + + user = User(id=session['welcome_user_id']) + encoded_img_data = base64.b64encode(user.get_qrcode_value()) + + if request.method == 'GET': + return render_template('register_otp.html', qrcode_image=encoded_img_data.decode(), user=user) + elif request.method == 'POST': + otp_token = request.form.get('otptoken', '') + if otp_token and otp_token.isdigit(): + good_token = user.verify_totp(otp_token) + if not good_token: + return render_template('register_otp.html', qrcode_image=encoded_img_data.decode(), user=user, error="Invalid token") + else: + return render_template('register_otp.html', qrcode_image=encoded_img_data.decode(), user=user, error="Token required") + session.pop('welcome_user_id') + return redirect(url_for('index.index')) + @index_bp.route('/confirm/', methods=['GET']) def confirm_email(token): email = confirm_token(token) @@ -1037,9 +1071,7 @@ def saml_authorized(): user.plain_text_password = None user.update_profile() session['authentication_type'] = 'SAML' - login_user(user, remember=False) - signin_history(user.username, 'SAML', True) - return redirect(url_for('index.login')) + return authenticate_user(user, 'SAML') else: return render_template('errors/SAML.html', errors=errors) diff --git a/powerdnsadmin/routes/user.py b/powerdnsadmin/routes/user.py index 6ca927b..f411c29 100644 --- a/powerdnsadmin/routes/user.py +++ b/powerdnsadmin/routes/user.py @@ -1,7 +1,4 @@ import datetime -import qrcode as qrc -import qrcode.image.svg as qrc_svg -from io import BytesIO from flask import Blueprint, request, render_template, make_response, jsonify, redirect, url_for, g, session, current_app from flask_login import current_user, login_required, login_manager @@ -94,13 +91,9 @@ def qrcode(): if not current_user: return redirect(url_for('index')) - img = qrc.make(current_user.get_totp_uri(), - image_factory=qrc_svg.SvgPathImage) - stream = BytesIO() - img.save(stream) - return stream.getvalue(), 200, { + return current_user.get_qrcode_value(), 200, { 'Content-Type': 'image/svg+xml', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' - } + } \ No newline at end of file diff --git a/powerdnsadmin/static/custom/js/custom.js b/powerdnsadmin/static/custom/js/custom.js index 9bd9669..395e1ac 100644 --- a/powerdnsadmin/static/custom/js/custom.js +++ b/powerdnsadmin/static/custom/js/custom.js @@ -285,4 +285,14 @@ function timer(elToUpdate, maxTime) { }, 1000); return interval; -} \ No newline at end of file +} + +// copy otp secret code to clipboard +function copy_otp_secret_to_clipboard() { + var copyBox = document.getElementById("otp_secret"); + copyBox.select(); + copyBox.setSelectionRange(0, 99999); /* For mobile devices */ + navigator.clipboard.writeText(copyBox.value); + $("#copy_tooltip").css("visibility", "visible"); + setTimeout(function(){ $("#copy_tooltip").css("visibility", "collapse"); }, 2000); + } \ No newline at end of file diff --git a/powerdnsadmin/templates/register_otp.html b/powerdnsadmin/templates/register_otp.html new file mode 100755 index 0000000..68e7ab8 --- /dev/null +++ b/powerdnsadmin/templates/register_otp.html @@ -0,0 +1,90 @@ + + + + + + + Welcome - {{ SITE_NAME }} + + + + {% assets "css_login" -%} + + {%- endassets %} + {% if SETTING.get('custom_css') %} + + {% endif %} + + + +
+ +
+ {% if error %} +
+ + {{ error }} +
+ {% endif %} + Welcome, {{user.firstname}}!
+ You will need a Token on login.
+ Your QR code is: +
+ {% if qrcode_image == None %} +

+ {% else %} +

+ {% endif %} +

+ Your secret key is:
+

+ + +
Copied. +
+

+ You can use Google Authenticator (Android + - iOS) +
+ or FreeOTP (Android + - iOS) + on your smartphone
to scan the QR code or type the secret key. +

+ Make sure only you can see this QR Code
+ and secret key, and nobody can capture them.
+
+
+ Please input your OTP token to continue, to ensure the seed has been scanned correctly. +
+ +
+ +
+
+
+ +
+
+
+
+ +
+ + {% assets "js_login" -%} + + {%- endassets %} + {% assets "js_validation" -%} + + {%- endassets %} + \ No newline at end of file diff --git a/powerdnsadmin/templates/user_profile.html b/powerdnsadmin/templates/user_profile.html index a13d3d3..8570f7e 100644 --- a/powerdnsadmin/templates/user_profile.html +++ b/powerdnsadmin/templates/user_profile.html @@ -93,6 +93,14 @@ {% if current_user.otp_secret %}

+
+ Your secret key is:
+
+ + +
Copied. +
+
You can use Google Authenticator (Android - iOS) on your smartphone to scan the QR code.
- Make sure only you can see this QR Code and - nobody can capture it. + Make sure only you can see this QR Code and secret key and + nobody can capture them.
{% endif %} From 9ef0f2b8d6982d460eac49a8db576eb3a7adab76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:59:34 +0000 Subject: [PATCH 005/203] Bump python-ldap from 3.3.1 to 3.4.0 Bumps [python-ldap](https://github.com/python-ldap/python-ldap) from 3.3.1 to 3.4.0. - [Release notes](https://github.com/python-ldap/python-ldap/releases) - [Commits](https://github.com/python-ldap/python-ldap/compare/python-ldap-3.3.1...python-ldap-3.4.0) --- updated-dependencies: - dependency-name: python-ldap dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5e97a12..c33d0ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ mysqlclient==2.0.1 configobj==5.0.6 bcrypt>=3.1.7 requests==2.24.0 -python-ldap==3.3.1 +python-ldap==3.4.0 pyotp==2.4.0 qrcode==6.1 dnspython>=1.16.0 From 7808febad8fb0a56cdecce2d7cdb9a92ec30ff06 Mon Sep 17 00:00:00 2001 From: zoeller-freinet <86965592+zoeller-freinet@users.noreply.github.com> Date: Fri, 17 Dec 2021 12:48:11 +0100 Subject: [PATCH 006/203] login.html: don't suggest previous OTP tokens This change has been tested to work with: - Chromium 96.0.4664.93 - Firefox 95.0 - Edge 96.0.1054.57 --- powerdnsadmin/templates/login.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdnsadmin/templates/login.html b/powerdnsadmin/templates/login.html index dcf96cf..6b017af 100644 --- a/powerdnsadmin/templates/login.html +++ b/powerdnsadmin/templates/login.html @@ -50,7 +50,7 @@ {% if SETTING.get('otp_field_enabled') %}
- +
{% endif %} {% if SETTING.get('ldap_enabled') and SETTING.get('local_db_enabled') %} From 328780e2d41b7120afecf22c83b8d88864eaeaf7 Mon Sep 17 00:00:00 2001 From: RGanor <44501230+RGanor@users.noreply.github.com> Date: Sat, 25 Dec 2021 16:17:54 +0200 Subject: [PATCH 007/203] Revert "Merge branch 'master' into master" This reverts commit ca4c145a1809b3fee8510b49fb517a844c3524eb, reversing changes made to 7808febad8fb0a56cdecce2d7cdb9a92ec30ff06. --- powerdnsadmin/routes/dashboard.py | 1 - 1 file changed, 1 deletion(-) diff --git a/powerdnsadmin/routes/dashboard.py b/powerdnsadmin/routes/dashboard.py index a23ffa1..8cf1b12 100644 --- a/powerdnsadmin/routes/dashboard.py +++ b/powerdnsadmin/routes/dashboard.py @@ -208,7 +208,6 @@ def dashboard(): history_number=history_number, uptime=uptime, histories=detailedHistories, - histories=history, show_bg_domain_button=show_bg_domain_button, pdns_version=Setting().get('pdns_version')) From 302e793665a54ce6b083133f471edfc1cf120e96 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 31 Dec 2021 00:55:59 +0100 Subject: [PATCH 008/203] Add button for admin page in single Domain view (#1076) * Added button for admin page in domain overview --- powerdnsadmin/templates/domain.html | 5 +++++ 1 file changed, 5 insertions(+) mode change 100644 => 100755 powerdnsadmin/templates/domain.html diff --git a/powerdnsadmin/templates/domain.html b/powerdnsadmin/templates/domain.html old mode 100644 new mode 100755 index 3ac96d1..8366c74 --- a/powerdnsadmin/templates/domain.html +++ b/powerdnsadmin/templates/domain.html @@ -33,6 +33,11 @@ Update from Master  {% endif %} + {% if current_user.role.name in ['Administrator', 'Operator'] %} + + {% endif %} {% if current_user.role.name in ['Administrator', 'Operator'] or SETTING.get('allow_user_view_history') %} @@ -45,17 +46,10 @@ - - \ No newline at end of file + diff --git a/powerdnsadmin/templates/dashboard.html b/powerdnsadmin/templates/dashboard.html index e018be3..0e5b3b5 100755 --- a/powerdnsadmin/templates/dashboard.html +++ b/powerdnsadmin/templates/dashboard.html @@ -114,20 +114,20 @@ {{ history.history.msg }} {{ history.history.created_on }} + @@ -243,7 +243,8 @@ $(document.body).on('click', '.history-info-button', function () { var modal = $("#modal_history_info"); - var info = $(this).val(); + var history_id = $(this).val(); + var info = $("#history-info-div-" + history_id).html(); $('#modal-info-content').html(info); modal.modal('show'); }); From 98bd9634a4f02c072691932bc7e4c3cd5cb70e94 Mon Sep 17 00:00:00 2001 From: Adrien Delle Cave Date: Wed, 19 Jan 2022 13:50:12 +0100 Subject: [PATCH 010/203] [BUG] Fixed delete zone from API --- powerdnsadmin/routes/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdnsadmin/routes/api.py b/powerdnsadmin/routes/api.py index 4fce368..c44dfbc 100644 --- a/powerdnsadmin/routes/api.py +++ b/powerdnsadmin/routes/api.py @@ -287,7 +287,7 @@ def api_login_delete_zone(domain_name): domain.update() history = History(msg='Delete domain {0}'.format( - pretty_domain_name(domain_name)), + utils.pretty_domain_name(domain_name)), detail='', created_by=current_user.username, domain_id=domain_id) From cd94b5c0ac5739dee0aa7ec7249f4ac3fd37e85d Mon Sep 17 00:00:00 2001 From: dapillc <95588573+dapillc@users.noreply.github.com> Date: Wed, 19 Jan 2022 09:49:30 -0600 Subject: [PATCH 011/203] Update API.md (#1100) armless > harmless --- docs/API.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API.md b/docs/API.md index 890f556..d7e3732 100644 --- a/docs/API.md +++ b/docs/API.md @@ -18,7 +18,7 @@ The PDA API consists of two distinct parts: The requests to the API needs two headers: -- The classic 'Content-Type: application/json' is required to all POST and PUT requests, though it's armless to use it on each call +- The classic 'Content-Type: application/json' is required to all POST and PUT requests, though it's harmless to use it on each call - The authentication header to provide either the login:password basic authentication or the Api Key authentication. When you access the `/powerdnsadmin` endpoint, you must use the Basic Auth: From 6982e0107cbec2c134006fc303662541a8bb3689 Mon Sep 17 00:00:00 2001 From: Adrien Delle Cave Date: Thu, 20 Jan 2022 12:49:37 +0100 Subject: [PATCH 012/203] Typo in routes/api.py --- powerdnsadmin/routes/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerdnsadmin/routes/api.py b/powerdnsadmin/routes/api.py index c44dfbc..9668176 100644 --- a/powerdnsadmin/routes/api.py +++ b/powerdnsadmin/routes/api.py @@ -1175,7 +1175,7 @@ def api_server_config_forward(server_id): resp = helper.forward_request() return resp.content, resp.status_code, resp.headers.items() -# The endpoint to snychronize Domains in background +# The endpoint to synchronize Domains in background @api_bp.route('/sync_domains', methods=['GET']) @apikey_or_basic_auth def sync_domains(): From b9cf7245a539e44dca4a6def9cfe39bac1265f0f Mon Sep 17 00:00:00 2001 From: kkmanos Date: Thu, 17 Feb 2022 17:02:11 +0200 Subject: [PATCH 013/203] fixed csrf expiration for login page --- powerdnsadmin/templates/login.html | 1 + 1 file changed, 1 insertion(+) diff --git a/powerdnsadmin/templates/login.html b/powerdnsadmin/templates/login.html index 6b017af..5ef3d39 100644 --- a/powerdnsadmin/templates/login.html +++ b/powerdnsadmin/templates/login.html @@ -21,6 +21,7 @@ +