Compare commits

...
Author SHA1 Message Date
Raphael Michel e4823720c7 Tests: Do not rely on actual DNS for peppol validation 2026-10-28 09:52:03 +01:00
2 changed files with 33 additions and 22 deletions

No files matched your search

+22 -19
View File
@@ -131,6 +131,27 @@ class PeppolIdValidator:
def __init__(self, validate_online=False):
self.validate_online = validate_online
def _validate_peppol_id_online(self, value):
base_hostnames = ['participant.sml.prod.tech.peppol.org', 'participant.sml.test.tech.peppol.org']
smp_id = base64.b32encode(hashlib.sha256(value.lower().encode()).digest()).decode().rstrip("=")
for base_hostname in base_hostnames:
smp_domain = f'{smp_id}.iso6523-actorid-upis.{base_hostname}'
resolver = dns.resolver.Resolver()
try:
answers = resolver.resolve(smp_domain, 'NAPTR', lifetime=1.0)
if answers:
return value
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# ID not registered, do not set found=True
pass
except Exception: # noqa
# Error likely on our end or infrastructure is down, allow user to proceed
return value
raise ValidationError(
_("The Peppol participant ID is not registered on the Peppol network."),
)
def __call__(self, value):
if ":" not in value:
raise ValidationError(_("A Peppol participant ID always starts with a prefix, followed by a colon (:)."))
@@ -146,25 +167,7 @@ class PeppolIdValidator:
params={"number": prefix})
if self.validate_online:
base_hostnames = ['participant.sml.prod.tech.peppol.org', 'participant.sml.test.tech.peppol.org']
smp_id = base64.b32encode(hashlib.sha256(value.lower().encode()).digest()).decode().rstrip("=")
for base_hostname in base_hostnames:
smp_domain = f'{smp_id}.iso6523-actorid-upis.{base_hostname}'
resolver = dns.resolver.Resolver()
try:
answers = resolver.resolve(smp_domain, 'NAPTR', lifetime=1.0)
if answers:
return value
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
# ID not registered, do not set found=True
pass
except Exception: # noqa
# Error likely on our end or infrastructure is down, allow user to proceed
return value
raise ValidationError(
_("The Peppol participant ID is not registered on the Peppol network."),
)
value = self._validate_peppol_id_online(value)
return value
+11 -3
View File
@@ -26,6 +26,7 @@ from unittest import mock
import pytest
from django.core import mail as djmail
from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile
from django.utils.timezone import now
from django_countries.fields import Country
@@ -248,7 +249,14 @@ def test_order_update_state_validation(token_client, organizer, event, order):
@pytest.mark.django_db
def test_order_update_transmission_validation(token_client, organizer, event, order):
def test_order_update_transmission_validation(token_client, organizer, event, order, monkeypatch):
def mock_validate(self, value):
if value == "9930:DE111111111":
return value
raise ValidationError("Invalid")
monkeypatch.setattr("pretix.base.invoicing.peppol.PeppolIdValidator._validate_peppol_id_online", mock_validate)
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
organizer.slug, event.slug, order.code
@@ -374,7 +382,7 @@ def test_order_update_transmission_validation(token_client, organizer, event, or
"vat_id": "",
"transmission_type": "peppol",
"transmission_info": {
"transmission_peppol_participant_id": "9930:DE811569869",
"transmission_peppol_participant_id": "9930:DE111111111",
"ignored": "parameter",
},
}
@@ -384,7 +392,7 @@ def test_order_update_transmission_validation(token_client, organizer, event, or
order.invoice_address.refresh_from_db()
assert order.invoice_address.transmission_type == "peppol"
assert order.invoice_address.transmission_info == {
"transmission_peppol_participant_id": "9930:DE811569869",
"transmission_peppol_participant_id": "9930:DE111111111",
}