from urllib.parse import quote import pytest from fansifter_common.encrypter import Encrypter from fansifter_common.identifiers.exceptions import ( InvalidDoubleOptInTokenError, InvalidProfileTokenError, ) from fansifter_common.identifiers.types import ( CRMProfileIdentifier, DoubleOptInIdentifier, DoubleOptInToken, FansifterProfileIdentifier, ProfileIdentifier, ProfileToken, ) from fansifter_common.identifiers.utils import ( decrypt_double_opt_in_identifier, decrypt_profile_identifier, encrypt_double_opt_in_token, encrypt_profile_token, ) @pytest.mark.parametrize( "identifier", [ FansifterProfileIdentifier.model_construct(profile_id="profile"), FansifterProfileIdentifier.model_construct( profile_id="profile", email_campaign_id="campaign" ), CRMProfileIdentifier.model_construct(crm_id="crm"), CRMProfileIdentifier.model_construct( crm_id="crm", email_campaign_id="campaign" ), ], ) def test_profile_identifier( encrypter: Encrypter, identifier: ProfileIdentifier ) -> None: token = encrypt_profile_token(encrypter, identifier=identifier) assert decrypt_profile_identifier(encrypter, token=token) == identifier def test_decrypt_invalid_profile_token(encrypter: Encrypter) -> None: with pytest.raises(InvalidProfileTokenError): decrypt_profile_identifier(encrypter, token=ProfileToken("invalid")) def test_double_opt_in_encrypt_decrypt_round_trip(encrypter: Encrypter) -> None: identifier = DoubleOptInIdentifier.model_construct( event_row_id="row-123", email_id="email-456", automated_email_trigger_id="trigger-789", iat=1700000000.0, ) token = encrypt_double_opt_in_token(encrypter, identifier=identifier) result = decrypt_double_opt_in_identifier(encrypter, token=token) assert result == identifier def test_double_opt_in_decrypt_url_encoded_token(encrypter: Encrypter) -> None: identifier = DoubleOptInIdentifier.model_construct( event_row_id="row-123", email_id="email-456", automated_email_trigger_id="trigger-789", iat=1700000000.0, ) token = encrypt_double_opt_in_token(encrypter, identifier=identifier) url_encoded_token = DoubleOptInToken(quote(token)) result = decrypt_double_opt_in_identifier(encrypter, token=url_encoded_token) assert result == identifier def test_double_opt_in_decrypt_invalid_token(encrypter: Encrypter) -> None: with pytest.raises(InvalidDoubleOptInTokenError): decrypt_double_opt_in_identifier( encrypter, token=DoubleOptInToken("invalid-token") ) def test_double_opt_in_decrypt_empty_token(encrypter: Encrypter) -> None: with pytest.raises(InvalidDoubleOptInTokenError): decrypt_double_opt_in_identifier(encrypter, token=DoubleOptInToken("")) def test_double_opt_in_decrypt_malformed_json(encrypter: Encrypter) -> None: token = DoubleOptInToken(encrypter.encrypt(b"not-json").decode()) with pytest.raises(InvalidDoubleOptInTokenError): decrypt_double_opt_in_identifier(encrypter, token=token)