111 lines
4.2 KiB
Python
111 lines
4.2 KiB
Python
import pytest
|
|
from cryptography.fernet import Fernet
|
|
from django.core.exceptions import ValidationError
|
|
from django.test import override_settings
|
|
|
|
from apps.sources.models import MailboxConnection
|
|
from apps.sources.services.imap_import import poll_imap_mailbox
|
|
from apps.sources.services.mailbox_connections import (
|
|
MailboxCredentialError,
|
|
decrypt_mailbox_password,
|
|
encrypt_mailbox_password,
|
|
rotate_mailbox_credentials,
|
|
)
|
|
from apps.sources.services.url_security import UnsafeUrlError
|
|
|
|
|
|
def test_mailbox_password_is_encrypted_and_supports_key_rotation():
|
|
old_key = Fernet.generate_key().decode("ascii")
|
|
new_key = Fernet.generate_key().decode("ascii")
|
|
with override_settings(MAILBOX_CREDENTIAL_KEYS=[old_key]):
|
|
ciphertext = encrypt_mailbox_password("app-password-value")
|
|
|
|
connection = MailboxConnection(encrypted_password=ciphertext)
|
|
assert "app-password-value" not in ciphertext
|
|
with override_settings(MAILBOX_CREDENTIAL_KEYS=[new_key, old_key]):
|
|
assert decrypt_mailbox_password(connection) == "app-password-value"
|
|
rotated = encrypt_mailbox_password("replacement-value")
|
|
assert Fernet(new_key.encode("ascii")).decrypt(rotated.encode("ascii")) == b"replacement-value"
|
|
|
|
|
|
def test_mailbox_password_fails_closed_without_valid_key():
|
|
with (
|
|
override_settings(MAILBOX_CREDENTIAL_KEYS=[]),
|
|
pytest.raises(MailboxCredentialError, match="niet geconfigureerd"),
|
|
):
|
|
encrypt_mailbox_password("never-stored")
|
|
with (
|
|
override_settings(MAILBOX_CREDENTIAL_KEYS=["invalid"]),
|
|
pytest.raises(MailboxCredentialError, match="ongeldige sleutel"),
|
|
):
|
|
encrypt_mailbox_password("never-stored")
|
|
|
|
|
|
@pytest.mark.parametrize("host", ["", "https://imap.example.org", "imap.example.org/path", "a b"])
|
|
def test_custom_mailbox_host_rejects_non_hostname_values(host):
|
|
connection = MailboxConnection(
|
|
platform=MailboxConnection.Platform.VDAB,
|
|
provider=MailboxConnection.Provider.CUSTOM,
|
|
custom_host=host,
|
|
port=993,
|
|
username="mailbox@example.invalid",
|
|
encrypted_password="ciphertext",
|
|
)
|
|
with pytest.raises(ValidationError):
|
|
connection.clean()
|
|
|
|
|
|
@pytest.mark.parametrize("port", [0, 65536])
|
|
def test_mailbox_rejects_invalid_port(port):
|
|
connection = MailboxConnection(
|
|
platform=MailboxConnection.Platform.VDAB,
|
|
provider=MailboxConnection.Provider.GMAIL,
|
|
port=port,
|
|
username="mailbox@example.invalid",
|
|
encrypted_password="ciphertext",
|
|
)
|
|
with pytest.raises(ValidationError):
|
|
connection.clean()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_rotation_reencrypts_existing_credentials_with_primary_key(user):
|
|
old_key = Fernet.generate_key().decode("ascii")
|
|
new_key = Fernet.generate_key().decode("ascii")
|
|
with override_settings(MAILBOX_CREDENTIAL_KEYS=[old_key]):
|
|
ciphertext = encrypt_mailbox_password("rotate-me")
|
|
connection = MailboxConnection.objects.create(
|
|
user=user,
|
|
platform=MailboxConnection.Platform.VDAB,
|
|
provider=MailboxConnection.Provider.GMAIL,
|
|
username="rotate@example.invalid",
|
|
encrypted_password=ciphertext,
|
|
)
|
|
|
|
with override_settings(MAILBOX_CREDENTIAL_KEYS=[new_key, old_key]):
|
|
assert rotate_mailbox_credentials() == 1
|
|
connection.refresh_from_db()
|
|
with override_settings(MAILBOX_CREDENTIAL_KEYS=[new_key]):
|
|
assert decrypt_mailbox_password(connection) == "rotate-me"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_private_imap_host_is_blocked_before_connection(user):
|
|
key = Fernet.generate_key().decode("ascii")
|
|
with override_settings(MAILBOX_CREDENTIAL_KEYS=[key]):
|
|
connection = MailboxConnection.objects.create(
|
|
user=user,
|
|
platform=MailboxConnection.Platform.VDAB,
|
|
provider=MailboxConnection.Provider.CUSTOM,
|
|
custom_host="127.0.0.1",
|
|
username="private@example.invalid",
|
|
encrypted_password=encrypt_mailbox_password("never-sent"),
|
|
)
|
|
with pytest.raises(UnsafeUrlError, match="Niet-publiek"):
|
|
poll_imap_mailbox(
|
|
connection,
|
|
client_factory=lambda *args, **kwargs: pytest.fail(
|
|
"Private IMAP-host had niet geconnecteerd mogen worden"
|
|
),
|
|
)
|