# Path: src/cybersource/signature.py
# class SecureAcceptanceSigner(object):
#     def __init__(self, secret_key):
#         self.secret_key = secret_key
# 
#     def sign(self, data, signed_fields):
#         key = self.secret_key.encode("utf-8")
#         msg_raw = self._build_message(data, signed_fields).encode("utf-8")
#         msg_hmac = hmac.new(key, msg_raw, hashlib.sha256)
#         return base64.b64encode(msg_hmac.digest())
# 
#     def verify_request(self, request):
#         # Ensure the signature is valid and that this request can be trusted
#         signed_field_names = request.POST.get("signed_field_names")
#         if not signed_field_names:
#             raise SuspiciousOperation("Request has no fields to verify")
#         signed_field_names = signed_field_names.split(",")
#         signature_given = request.POST["signature"].encode("utf-8")
#         signature_calc = self.sign(request.POST, signed_field_names)
#         return signature_given == signature_calc
# 
#     def _build_message(self, data, signed_fields):
#         parts = []
#         for field in signed_fields:
#             parts.append("%s=%s" % (field, data.get(field, "")))
#         return ",".join(parts)
# 
# Path: src/cybersource/models.py
# class SecureAcceptanceProfile(models.Model):
#     hostname = models.CharField(
#         _("Hostname"),
#         max_length=100,
#         blank=True,
#         unique=True,
#         help_text=_(
#             "When the request matches this hostname, this profile will be used."
#         ),
#     )
#     profile_id = models.CharField(_("Profile ID"), max_length=50, unique=True)
#     access_key = models.CharField(_("Access Key"), max_length=50)
#     secret_key = EncryptedTextField(_("Secret Key"))
#     is_default = models.BooleanField(
#         _("Is Default Profile?"),
#         default=False,
#         help_text=_(
#             "If no profile can be found for a request's hostname, the default profile will be used."
#         ),
#     )
# 
#     class Meta:
#         verbose_name = _("Secure Acceptance Profile")
#         verbose_name_plural = _("Secure Acceptance Profiles")
# 
#     @classmethod
#     def get_profile(cls, hostname):
#         # Lambda function to get profiles whilst catching cryptography exceptions (in-case the Fernet key
#         # unexpectedly changed, the data somehow got corrupted, etc).
#         def _get_safe(**filters):
#             try:
#                 return cls.objects.filter(**filters).first()
#             except InvalidToken:
#                 logger.exception(
#                     "Caught InvalidToken exception while retrieving profile"
#                 )
#                 return None
# 
#         # Try to get the profile for the given hostname
#         profile = _get_safe(hostname__iexact=hostname)
#         if profile:
#             return profile
# 
#         # Fall back to the default profile
#         profile = _get_safe(is_default=True)
#         if profile:
#             return profile
# 
#         # No default profile exists, so try and get something out of settings.
#         if (
#             hasattr(settings, "CYBERSOURCE_PROFILE")
#             and hasattr(settings, "CYBERSOURCE_ACCESS")
#             and hasattr(settings, "CYBERSOURCE_SECRET")
#         ):
#             profile = SecureAcceptanceProfile()
#             profile.hostname = ""
#             profile.profile_id = settings.CYBERSOURCE_PROFILE
#             profile.access_key = settings.CYBERSOURCE_ACCESS
#             profile.secret_key = settings.CYBERSOURCE_SECRET
#             profile.is_default = True
#             profile.save()
#             logger.info(
#                 "Created SecureAcceptanceProfile from Django settings: {}".format(
#                     profile
#                 )
#             )
#             return profile
# 
#         # Out of options—raise an exception.
#         raise cls.DoesNotExist()
# 
#     def save(self, *args, **kwargs):
#         if self.is_default:
#             self.__class__._default_manager.filter(is_default=True).update(
#                 is_default=False
#             )
#         return super().save(*args, **kwargs)
# 
#     def __str__(self):
#         return _(
#             "Secure Acceptance Profile hostname=%(hostname)s, profile_id=%(profile_id)s"
#         ) % dict(hostname=self.hostname, profile_id=self.profile_id)
# 
# Path: src/cybersource/actions.py
# def encrypt_session_id(session_id):
#     fernet = EncryptedTextField().fernet
#     session_id_bytes = force_bytes(session_id)
#     encrypted_bytes = fernet.encrypt(session_id_bytes)
#     encrypted_str = force_str(encrypted_bytes)
#     return encrypted_str


from datetime import datetime
from random import randrange
from ..signature import SecureAcceptanceSigner
from ..models import SecureAcceptanceProfile
from ..actions import encrypt_session_id
import uuid
        "req_transaction_uuid": str(randrange(100000000000, 999999999999)),
        "request_token": "Ahj/7wSR8sYxolZgxwyeIkG7lw3ZNnDmLNjMqcSPOS4lfDoTAFLiV8OhM0glqN4vpQyaSZbpAd0+3AnI+WMY0SswY4ZPAAAALRaM",
        "req_merchant_secure_data4": encrypt_session_id(session_id),
        "score_bin_country": "US",
        "score_card_issuer": "JPMORGAN CHASE BANK, N.A.",
        "score_card_scheme": "VISA CREDIT",
        "score_host_severity": "1",
        "score_internet_info": "FREE-EM^MM-IPBC",
        "score_ip_city": "new york",
        "score_ip_country": "us",
        "score_ip_routing_method": "fixed",
        "score_ip_state": "ny",
        "score_model_used": "default",
        "score_rcode": "1",
        "score_reason_code": "480",
        "score_return_code": "1070000",
        "score_rflag": "SOK",
        "score_rmsg": "score service was successful",
        "score_score_result": "0",
        "score_time_local": "10:06:36",
        "transaction_id": str(randrange(0, 99999999999999999999)),
        "utf8": "✓",
    }
    return data


def sign_reply_data(data):
    profile = get_sa_profile()
    fields = list(data.keys())
    data["signature"] = (

# Path: src/cybersource/signature.py
# class SecureAcceptanceSigner(object):
#     def __init__(self, secret_key):
#         self.secret_key = secret_key
# 
#     def sign(self, data, signed_fields):
#         key = self.secret_key.encode("utf-8")
#         msg_raw = self._build_message(data, signed_fields).encode("utf-8")
#         msg_hmac = hmac.new(key, msg_raw, hashlib.sha256)
#         return base64.b64encode(msg_hmac.digest())
# 
#     def verify_request(self, request):
#         # Ensure the signature is valid and that this request can be trusted
#         signed_field_names = request.POST.get("signed_field_names")
#         if not signed_field_names:
#             raise SuspiciousOperation("Request has no fields to verify")
#         signed_field_names = signed_field_names.split(",")
#         signature_given = request.POST["signature"].encode("utf-8")
#         signature_calc = self.sign(request.POST, signed_field_names)
#         return signature_given == signature_calc
# 
#     def _build_message(self, data, signed_fields):
#         parts = []
#         for field in signed_fields:
#             parts.append("%s=%s" % (field, data.get(field, "")))
#         return ",".join(parts)
# 
# Path: src/cybersource/models.py
# class SecureAcceptanceProfile(models.Model):
#     hostname = models.CharField(
#         _("Hostname"),
#         max_length=100,
#         blank=True,
#         unique=True,
#         help_text=_(
#             "When the request matches this hostname, this profile will be used."
#         ),
#     )
#     profile_id = models.CharField(_("Profile ID"), max_length=50, unique=True)
#     access_key = models.CharField(_("Access Key"), max_length=50)
#     secret_key = EncryptedTextField(_("Secret Key"))
#     is_default = models.BooleanField(
#         _("Is Default Profile?"),
#         default=False,
#         help_text=_(
#             "If no profile can be found for a request's hostname, the default profile will be used."
#         ),
#     )
# 
#     class Meta:
#         verbose_name = _("Secure Acceptance Profile")
#         verbose_name_plural = _("Secure Acceptance Profiles")
# 
#     @classmethod
#     def get_profile(cls, hostname):
#         # Lambda function to get profiles whilst catching cryptography exceptions (in-case the Fernet key
#         # unexpectedly changed, the data somehow got corrupted, etc).
#         def _get_safe(**filters):
#             try:
#                 return cls.objects.filter(**filters).first()
#             except InvalidToken:
#                 logger.exception(
#                     "Caught InvalidToken exception while retrieving profile"
#                 )
#                 return None
# 
#         # Try to get the profile for the given hostname
#         profile = _get_safe(hostname__iexact=hostname)
#         if profile:
#             return profile
# 
#         # Fall back to the default profile
#         profile = _get_safe(is_default=True)
#         if profile:
#             return profile
# 
#         # No default profile exists, so try and get something out of settings.
#         if (
#             hasattr(settings, "CYBERSOURCE_PROFILE")
#             and hasattr(settings, "CYBERSOURCE_ACCESS")
#             and hasattr(settings, "CYBERSOURCE_SECRET")
#         ):
#             profile = SecureAcceptanceProfile()
#             profile.hostname = ""
#             profile.profile_id = settings.CYBERSOURCE_PROFILE
#             profile.access_key = settings.CYBERSOURCE_ACCESS
#             profile.secret_key = settings.CYBERSOURCE_SECRET
#             profile.is_default = True
#             profile.save()
#             logger.info(
#                 "Created SecureAcceptanceProfile from Django settings: {}".format(
#                     profile
#                 )
#             )
#             return profile
# 
#         # Out of options—raise an exception.
#         raise cls.DoesNotExist()
# 
#     def save(self, *args, **kwargs):
#         if self.is_default:
#             self.__class__._default_manager.filter(is_default=True).update(
#                 is_default=False
#             )
#         return super().save(*args, **kwargs)
# 
#     def __str__(self):
#         return _(
#             "Secure Acceptance Profile hostname=%(hostname)s, profile_id=%(profile_id)s"
#         ) % dict(hostname=self.hostname, profile_id=self.profile_id)
# 
# Path: src/cybersource/actions.py
# def encrypt_session_id(session_id):
#     fernet = EncryptedTextField().fernet
#     session_id_bytes = force_bytes(session_id)
#     encrypted_bytes = fernet.encrypt(session_id_bytes)
#     encrypted_str = force_str(encrypted_bytes)
#     return encrypted_str


# Path: src/cybersource/tests/factories.py
from datetime import datetime
from random import randrange
from ..signature import SecureAcceptanceSigner
from ..models import SecureAcceptanceProfile
from ..actions import encrypt_session_id
import uuid

        "req_transaction_uuid": str(randrange(100000000000, 999999999999)),
        "request_token": "Ahj/7wSR8sYxolZgxwyeIkG7lw3ZNnDmLNjMqcSPOS4lfDoTAFLiV8OhM0glqN4vpQyaSZbpAd0+3AnI+WMY0SswY4ZPAAAALRaM",
        "req_merchant_secure_data4": encrypt_session_id(session_id),
        "score_bin_country": "US",
        "score_card_issuer": "JPMORGAN CHASE BANK, N.A.",
        "score_card_scheme": "VISA CREDIT",
        "score_host_severity": "1",
        "score_internet_info": "FREE-EM^MM-IPBC",
        "score_ip_city": "new york",
        "score_ip_country": "us",
        "score_ip_routing_method": "fixed",
        "score_ip_state": "ny",
        "score_model_used": "default",
        "score_rcode": "1",
        "score_reason_code": "480",
        "score_return_code": "1070000",
        "score_rflag": "SOK",
        "score_rmsg": "score service was successful",
        "score_score_result": "0",
        "score_time_local": "10:06:36",
        "transaction_id": str(randrange(0, 99999999999999999999)),
        "utf8": "✓",
    }
    return data


def sign_reply_data(data):
    profile = get_sa_profile()
    fields = list(data.keys())
    data["signature"] = (

        SecureAcceptanceSigner(profile.secret_key).sign(data, fields).decode("utf8")