Skip to content
This repository has been archived by the owner on Mar 19, 2024. It is now read-only.

Commit

Permalink
Release 3.10.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
IngenicoEPayments authored and jenkins committed May 19, 2020
1 parent 434e72d commit 5733eb7
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 46 deletions.
16 changes: 14 additions & 2 deletions README.md
Expand Up @@ -29,8 +29,8 @@ Note that the source code of the unit tests and integration tests and the exampl

Python 3.3.5 or higher is required. In addition, the following packages are required:

* [django](https://www.djangoproject.com/) 1.10 or higher
* [requests](http://docs.python-requests.org/en/master/) 2.11.0 or higher
* [requests](https://requests.readthedocs.io/) 2.20.0 or higher
* **Note**: for Python 3.3, the maximum supported version is 2.18.4. While this version will work, it has known vulnerabilities.
* [requests-toolbelt](https://toolbelt.readthedocs.io/) 0.8.0 or higher

These packages will be installed automatically if the SDK is installed manually or using pip following the below instructions.
Expand All @@ -50,6 +50,18 @@ Alternatively, you can install the SDK from a source distribution file:
pip install connect-sdk-python3-x.y.z.zip
```

### Python 3.3

When using Python 3.3, these commands will fail because the requests dependency is not supported. Instead, you need to install the dependencies separately:

pip install connect-sdk-python3 --no-deps
pip install requests requests-toolbelt

or

pip install connect-sdk-python3-x.y.z.zip --no-deps
pip install requests requests-toolbelt

## Uninstalling

After the Python SDK has been installed, it can be uninstalled using the following command:
Expand Down
29 changes: 26 additions & 3 deletions README.rst
Expand Up @@ -43,9 +43,11 @@ Requirements
Python 3.3.5 or higher is required. In addition, the following packages
are required:

- `django <https://www.djangoproject.com/>`__ 1.10 or higher
- `requests <http://docs.python-requests.org/en/master/>`__ 2.11.0 or
higher
- `requests <https://requests.readthedocs.io/>`__ 2.20.0 or higher

- **Note**: for Python 3.3, the maximum supported version is 2.18.4.
While this version will work, it has known vulnerabilities.

- `requests-toolbelt <https://toolbelt.readthedocs.io/>`__ 0.8.0 or
higher

Expand Down Expand Up @@ -75,6 +77,27 @@ Alternatively, you can install the SDK from a source distribution file:

pip install connect-sdk-python3-x.y.z.zip

.. _python-33:

Python 3.3
~~~~~~~~~~

When using Python 3.3, these commands will fail because the requests
dependency is not supported. Instead, you need to install the
dependencies separately:

::

pip install connect-sdk-python3 --no-deps
pip install requests requests-toolbelt

or

::

pip install connect-sdk-python3-x.y.z.zip --no-deps
pip install requests requests-toolbelt

Uninstalling
------------

Expand Down
6 changes: 3 additions & 3 deletions conf.py
Expand Up @@ -62,9 +62,9 @@
# built documents.
#
# The short X.Y version.
version = '3.9.0'
version = '3.10.0'
# The full version, including alpha/beta/rc tags.
release = '3.9.0'
release = '3.10.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down Expand Up @@ -138,7 +138,7 @@
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#
# html_title = 'Python SDK v3.9.0'
# html_title = 'Python SDK v3.10.0'

# A shorter title for the navigation bar. Default is the same as html_title.
#
Expand Down
5 changes: 5 additions & 0 deletions examples/merchant/payments/create_payment_example.py
Expand Up @@ -41,10 +41,15 @@ def example(self):
card.cvv = "123"
card.expiry_date = "1220"

authentication_amount = AmountOfMoney()
authentication_amount.amount = 2980
authentication_amount.currency_code = "EUR"

redirection_data = RedirectionData()
redirection_data.return_url = "https://hostname.myownwebsite.url"

three_d_secure = ThreeDSecure()
three_d_secure.authentication_amount = authentication_amount
three_d_secure.authentication_flow = "browser"
three_d_secure.challenge_canvas_size = "600x400"
three_d_secure.challenge_indicator = "challenge-requested"
Expand Down
24 changes: 3 additions & 21 deletions ingenico/connect/sdk/communicator.py
Expand Up @@ -2,9 +2,6 @@
from urllib.parse import quote
from urllib.parse import urlparse

from django.core.exceptions import ValidationError
from django.core.validators import URLValidator

from .communication_exception import CommunicationException
from ingenico.connect.sdk.log.logging_capable import LoggingCapable
from .not_found_exception import NotFoundException
Expand Down Expand Up @@ -305,19 +302,7 @@ def _to_absolute_uri(self, relative_path, request_parameters):
absolute_path = relative_path
else:
absolute_path = "/" + relative_path
if api_endpoint.port is None:
if api_endpoint.scheme:
uri = api_endpoint.scheme + "://" + api_endpoint.hostname + \
absolute_path
else:
uri = api_endpoint.hostname + absolute_path
else:
if api_endpoint.scheme:
uri = api_endpoint.scheme + "://" + api_endpoint.hostname + \
":" + str(api_endpoint.port) + absolute_path
else:
uri = api_endpoint.hostname + ":" + str(api_endpoint.port) + \
absolute_path
uri = api_endpoint.geturl() + absolute_path
flag = False
if request_parameters is not None:
for nvp in request_parameters:
Expand All @@ -327,11 +312,8 @@ def _to_absolute_uri(self, relative_path, request_parameters):
else:
uri += "&"
uri += quote(nvp.name) + "=" + quote(nvp.value)
try:
URLValidator(uri)
return urlparse(uri)
except ValidationError as e:
raise ValueError("Unable to construct URI", e)
# no need to revalidate that uri has a valid scheme and netloc
return urlparse(uri)

def _add_generic_headers(self, http_method, uri, request_headers, context):
"""
Expand Down
Expand Up @@ -4,12 +4,14 @@
# https://epayments-api.developer-ingenico.com/s2sapi/v1/
#
from ingenico.connect.sdk.data_object import DataObject
from ingenico.connect.sdk.domain.definitions.amount_of_money import AmountOfMoney
from ingenico.connect.sdk.domain.payment.definitions.sdk_data_input import SdkDataInput
from ingenico.connect.sdk.domain.payment.definitions.three_d_secure_data import ThreeDSecureData


class AbstractThreeDSecure(DataObject):

__authentication_amount = None
__authentication_flow = None
__challenge_canvas_size = None
__challenge_indicator = None
Expand All @@ -18,6 +20,17 @@ class AbstractThreeDSecure(DataObject):
__sdk_data = None
__skip_authentication = None

@property
def authentication_amount(self):
"""
Type: :class:`ingenico.connect.sdk.domain.definitions.amount_of_money.AmountOfMoney`
"""
return self.__authentication_amount

@authentication_amount.setter
def authentication_amount(self, value):
self.__authentication_amount = value

@property
def authentication_flow(self):
"""
Expand Down Expand Up @@ -97,6 +110,8 @@ def skip_authentication(self, value):

def to_dictionary(self):
dictionary = super(AbstractThreeDSecure, self).to_dictionary()
if self.authentication_amount is not None:
dictionary['authenticationAmount'] = self.authentication_amount.to_dictionary()
if self.authentication_flow is not None:
dictionary['authenticationFlow'] = self.authentication_flow
if self.challenge_canvas_size is not None:
Expand All @@ -115,6 +130,11 @@ def to_dictionary(self):

def from_dictionary(self, dictionary):
super(AbstractThreeDSecure, self).from_dictionary(dictionary)
if 'authenticationAmount' in dictionary:
if not isinstance(dictionary['authenticationAmount'], dict):
raise TypeError('value \'{}\' is not a dictionary'.format(dictionary['authenticationAmount']))
value = AmountOfMoney()
self.authentication_amount = value.from_dictionary(dictionary['authenticationAmount'])
if 'authenticationFlow' in dictionary:
self.authentication_flow = dictionary['authenticationFlow']
if 'challengeCanvasSize' in dictionary:
Expand Down
Expand Up @@ -4,6 +4,7 @@
# https://epayments-api.developer-ingenico.com/s2sapi/v1/
#
from ingenico.connect.sdk.data_object import DataObject
from ingenico.connect.sdk.domain.definitions.amount_of_money import AmountOfMoney
from ingenico.connect.sdk.domain.payment.definitions.sdk_data_output import SdkDataOutput
from ingenico.connect.sdk.domain.payment.definitions.three_d_secure_data import ThreeDSecureData

Expand All @@ -15,6 +16,7 @@ class ThreeDSecureResults(DataObject):

__acs_transaction_id = None
__applied_exemption = None
__authentication_amount = None
__cavv = None
__directory_server_transaction_id = None
__eci = None
Expand Down Expand Up @@ -51,6 +53,20 @@ def applied_exemption(self):
def applied_exemption(self, value):
self.__applied_exemption = value

@property
def authentication_amount(self):
"""
| Allows you to send in an authentication amount which can be greater or equal to the order amount.
| The currency code of the authentication amount should be the same as the currency code of the order amount.
Type: :class:`ingenico.connect.sdk.domain.definitions.amount_of_money.AmountOfMoney`
"""
return self.__authentication_amount

@authentication_amount.setter
def authentication_amount(self, value):
self.__authentication_amount = value

@property
def cavv(self):
"""
Expand Down Expand Up @@ -176,6 +192,8 @@ def to_dictionary(self):
dictionary['acsTransactionId'] = self.acs_transaction_id
if self.applied_exemption is not None:
dictionary['appliedExemption'] = self.applied_exemption
if self.authentication_amount is not None:
dictionary['authenticationAmount'] = self.authentication_amount.to_dictionary()
if self.cavv is not None:
dictionary['cavv'] = self.cavv
if self.directory_server_transaction_id is not None:
Expand All @@ -202,6 +220,11 @@ def from_dictionary(self, dictionary):
self.acs_transaction_id = dictionary['acsTransactionId']
if 'appliedExemption' in dictionary:
self.applied_exemption = dictionary['appliedExemption']
if 'authenticationAmount' in dictionary:
if not isinstance(dictionary['authenticationAmount'], dict):
raise TypeError('value \'{}\' is not a dictionary'.format(dictionary['authenticationAmount']))
value = AmountOfMoney()
self.authentication_amount = value.from_dictionary(dictionary['authenticationAmount'])
if 'cavv' in dictionary:
self.cavv = dictionary['cavv']
if 'directoryServerTransactionId' in dictionary:
Expand Down
Expand Up @@ -18,7 +18,7 @@ class GetIINDetailsRequest(DataObject):
@property
def bin(self):
"""
| The first digits of the credit card number from left to right with a minimum of 6 digits, or the full credit card number.
| The first digits of the credit card number from left to right with a minimum of 6 digits. Providing additional digits can result in more co-brands being returned.
Type: str
"""
Expand Down
12 changes: 4 additions & 8 deletions ingenico/connect/sdk/endpoint_configuration.py
@@ -1,9 +1,6 @@
from configparser import NoOptionError
from urllib.parse import urlparse

from django.core.exceptions import ValidationError
from django.core.validators import URLValidator

from ingenico.connect.sdk.domain.metadata.shopping_cart_extension import \
ShoppingCartExtension

Expand Down Expand Up @@ -99,11 +96,10 @@ def __create_uri(self, scheme, host, port):
uri = scheme + "://" + host + ":" + str(port)
else:
uri = scheme + "://" + host
try:
URLValidator(uri)
return urlparse(uri)
except ValidationError as e:
raise ValueError("Unable to construct endpoint URI", e)
url = urlparse(uri)
if not url.scheme.lower() in ["http", "https"] or not url.netloc:
raise ValueError("Unable to construct endpoint URI")
return url

def __get_shopping_cart_extension(self, properties, prefix):
try:
Expand Down
2 changes: 1 addition & 1 deletion ingenico/connect/sdk/log/logging_util.py
Expand Up @@ -82,7 +82,7 @@ def build_property_pattern(self, property_names):
s = "([\"'])("
for p in property_names:
s += '|' + re.escape(p)
s += ")\\1\\s*:\\s*(?:([\"'])(.*?)(?<!\\\\)\\3|([^\"'\\s\\[\\{]\\S*))"
s += ")\\1\\s*:\\s*(?:([\"'])(.*?)(?<!\\\\)\\3|([^\"'\\s\\[\\{]((?!,)\\S)*))"
return re.compile(s, re.DOTALL)

def obfuscate(self, body):
Expand Down
2 changes: 1 addition & 1 deletion ingenico/connect/sdk/meta_data_provider.py
Expand Up @@ -21,7 +21,7 @@ class MetaDataProvider:
"""
Provides meta info about the server.
"""
__SDK_VERSION = "3.9.0"
__SDK_VERSION = "3.10.0"
__SERVER_META_INFO_HEADER = "X-GCS-ServerMetaInfo"
__prohibited_headers = [__SERVER_META_INFO_HEADER, "X-GCS-Idempotence-Key",
"Date", "Content-Type", "Authorization"]
Expand Down
2 changes: 2 additions & 0 deletions ingenico/connect/sdk/session.py
Expand Up @@ -13,6 +13,8 @@ def __init__(self, api_endpoint, connection, authenticator,
raise ValueError("api_endpoint is required")
if isinstance(api_endpoint, str):
api_endpoint = urlparse(api_endpoint)
if not api_endpoint.scheme.lower() in ["http", "https"] or not api_endpoint.netloc:
raise ValueError("invalid api_endpoint: " + api_endpoint)
if api_endpoint.path:
raise ValueError("api_endpoint should not contain a path")
if api_endpoint.username is not None or api_endpoint.query or api_endpoint.fragment:
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Expand Up @@ -21,7 +21,7 @@ def test_collector():

setup(
name="connect-sdk-python3",
version="3.9.0",
version="3.10.0",
author="Ingenico ePayments",
author_email="github@epay.ingenico.com",
description="SDK to communicate with the Ingenico ePayments platform using the Ingenico Connect Server API",
Expand Down Expand Up @@ -53,8 +53,8 @@ def test_collector():
],
scripts=[], # executable python scripts, none since this is a library
install_requires=[
"requests >= 2.11.0",
"django >= 1.10"
"requests >= 2.20.0",
"requests-toolbelt >= 0.8.0"
],
# test_suite="tests/run_unit_tests" # enables command 'pip connect-sdk-python3 test', which runs unit tests)

Expand Down
4 changes: 2 additions & 2 deletions tests/resources/log/bodyWithObjectObfuscated.json
@@ -1,5 +1,5 @@
{
"value": *****
"value": ****,
"value": {
}
}
}
2 changes: 1 addition & 1 deletion tests/resources/log/bodyWithObjectOriginal.json
Expand Up @@ -2,4 +2,4 @@
"value": true,
"value": {
}
}
}

0 comments on commit 5733eb7

Please sign in to comment.