From 40deb3c145619067ff20af15b4a0d0c589d33322 Mon Sep 17 00:00:00 2001 From: AdvanticGmbH Date: Wed, 6 Apr 2022 14:59:59 +0200 Subject: [PATCH 1/2] Create method to encode and decode idna MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously strings with characters like "ß" would throw and exception This seems to happen because the lib behind encode().decode('idna') cant handle characters like this --- powerdnsadmin/lib/utils.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/powerdnsadmin/lib/utils.py b/powerdnsadmin/lib/utils.py index 951f750..9e7cf20 100644 --- a/powerdnsadmin/lib/utils.py +++ b/powerdnsadmin/lib/utils.py @@ -4,6 +4,7 @@ import json import requests import hashlib import ipaddress +import idna from collections.abc import Iterable from distutils.version import StrictVersion @@ -248,10 +249,27 @@ def pretty_domain_name(value): if value.startswith('xn--') \ or value.find('.xn--') != -1: try: - return value.encode().decode('idna') + return to_idna(value, 'decode') except: - raise Exception("Cannot decode IDN domain") + raise Exception('Cannot decode IDN domain') else: return value else: - raise Exception("Require the Punycode in string format") + raise Exception('Require the Punycode in string format') + +def to_idna(value, action): + splits = value.split() + result = [] + if action == 'encode': + for split in splits: + try: + # Try encoding to idna + result.append(idna.encode(split).decode()) + except idna.IDNAError: + result.append(split) + elif action == 'decode': + for split in splits: + result.append(idna.decode(split)) + else: + raise Exception('No valid action received') + return ' '.join(result) From 191e919626d396494c1197fa4405e158a6fc1251 Mon Sep 17 00:00:00 2001 From: AdvanticGmbH Date: Wed, 6 Apr 2022 17:01:28 +0200 Subject: [PATCH 2/2] Allow IDNA in SOA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Previously having characters like "ü" in the SOA wouldnt allow to push updates to the domain * Also use the new method to_idna to support characters like "ß" --- powerdnsadmin/models/record.py | 6 +++--- powerdnsadmin/routes/domain.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/powerdnsadmin/models/record.py b/powerdnsadmin/models/record.py index 9929b67..c19576a 100644 --- a/powerdnsadmin/models/record.py +++ b/powerdnsadmin/models/record.py @@ -169,12 +169,12 @@ class Record(object): record['record_data'] = record['record_data'].replace('[ZONE]', domain_name) # Translate record name into punycode (IDN) as that's the only way # to convey non-ascii records to the dns server - record['record_name'] = record['record_name'].encode('idna').decode() + record['record_name'] = utils.to_idna(record["record_name"], "encode") #TODO: error handling # If the record is an alias (CNAME), we will also make sure that # the target domain is properly converted to punycode (IDN) - if record["record_type"] == 'CNAME': - record['record_data'] = record['record_data'].encode('idna').decode() + if record['record_type'] == 'CNAME' or record['record_type'] == 'SOA': + record['record_data'] = utils.to_idna(record['record_data'], 'encode') #TODO: error handling # If it is ipv6 reverse zone and PRETTY_IPV6_PTR is enabled, # We convert ipv6 address back to reverse record format diff --git a/powerdnsadmin/routes/domain.py b/powerdnsadmin/routes/domain.py index e3b61cc..603a2a3 100644 --- a/powerdnsadmin/routes/domain.py +++ b/powerdnsadmin/routes/domain.py @@ -10,6 +10,7 @@ from flask_login import login_required, current_user, login_manager from ..lib.utils import pretty_domain_name from ..lib.utils import pretty_json +from ..lib.utils import to_idna from ..decorators import can_create_domain, operator_role_required, can_access_domain, can_configure_dnssec, can_remove_domain from ..models.user import User, Anonymous from ..models.account import Account @@ -379,7 +380,7 @@ def add(): # Encode domain name into punycode (IDN) try: - domain_name = domain_name.encode('idna').decode() + domain_name = to_idna(domain_name, 'encode') except: current_app.logger.error("Cannot encode the domain name {}".format(domain_name)) current_app.logger.debug(traceback.format_exc())