Skip to content

Commit 4bad89d

Browse files
committed
feature/python-sdk-psd2: ApiContext now supports PSD2.
1 parent 75a976d commit 4bad89d

File tree

1 file changed

+68
-18
lines changed

1 file changed

+68
-18
lines changed

bunq/sdk/context/api_context.py

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
from typing import List, Optional
66

77
from Cryptodome.PublicKey import RSA
8+
from Cryptodome.PublicKey.RSA import RsaKey
89

910
from bunq.sdk.context.api_environment_type import ApiEnvironmentType
1011
from bunq.sdk.context.installation_context import InstallationContext
1112
from bunq.sdk.context.session_context import SessionContext
1213
from bunq.sdk.exception.bunq_exception import BunqException
1314
from bunq.sdk.json import converter
15+
from bunq.sdk.model.core.PaymentServiceProviderCredentialInternal import PaymentServiceProviderCredentialInternal
1416
from bunq.sdk.model.generated import endpoint
17+
from bunq.sdk.model.generated.endpoint import UserCredentialPasswordIp
1518
from bunq.sdk.security import security
1619

1720
if typing.TYPE_CHECKING:
@@ -21,9 +24,9 @@
2124
class ApiContext:
2225
"""
2326
:type _environment_type: ApiEnvironmentType
24-
:type _api_key: str
25-
:type _session_context: SessionContext
26-
:type _installation_context: InstallationContext
27+
:type _api_key: str|None
28+
:type _session_context: SessionContext|None
29+
:type _installation_context: InstallationContext|None
2730
:type _proxy_url: str|None
2831
"""
2932

@@ -42,26 +45,54 @@ class ApiContext:
4245

4346
def __init__(self,
4447
environment_type: ApiEnvironmentType,
45-
api_key: str,
46-
device_description: str,
47-
permitted_ips: List[str] = None,
4848
proxy_url: List[str] = None) -> None:
49-
if permitted_ips is None:
50-
permitted_ips = []
51-
5249
self._environment_type = environment_type
53-
self._api_key = api_key
50+
self._proxy_url = proxy_url
51+
self._api_key = None
5452
self._installation_context = None
5553
self._session_context = None
56-
self._proxy_url = proxy_url
57-
self._initialize(device_description, permitted_ips)
5854

59-
def _initialize(self,
60-
device_description: str,
61-
permitted_ips: List[str]) -> None:
62-
self._initialize_installation()
63-
self._register_device(device_description, permitted_ips)
64-
self._initialize_session()
55+
@classmethod
56+
def create(cls,
57+
environment_type: ApiEnvironmentType,
58+
api_key: str,
59+
description: str,
60+
all_permitted_ip: List[str] = None,
61+
proxy_url: List[str] = None) -> ApiContext:
62+
api_context = cls(environment_type, proxy_url)
63+
64+
api_context._api_key = api_key
65+
66+
api_context._initialize_installation()
67+
api_context._register_device(description, all_permitted_ip)
68+
api_context._initialize_session()
69+
70+
return api_context
71+
72+
@classmethod
73+
def create_for_psd2(cls,
74+
environment_type: ApiEnvironmentType,
75+
certificate: str,
76+
private_key: RsaKey,
77+
all_chain_certificate: List[str],
78+
description: str,
79+
all_permitted_ip: List[str] = None,
80+
proxy_url: List[str] = None) -> ApiContext:
81+
api_context = cls(environment_type, proxy_url)
82+
83+
api_context._initialize_installation()
84+
85+
service_provider_credential = api_context._initialize_psd2_credential(
86+
certificate,
87+
private_key,
88+
all_chain_certificate)
89+
90+
api_context._api_key = service_provider_credential.token_value
91+
92+
api_context._register_device(description, all_permitted_ip)
93+
api_context._initialize_session()
94+
95+
return api_context
6596

6697
def _initialize_installation(self) -> None:
6798
from bunq.sdk.model.core.installation import Installation
@@ -83,6 +114,25 @@ def _initialize_installation(self) -> None:
83114
public_key_server
84115
)
85116

117+
def _initialize_psd2_credential(self,
118+
certificate: str,
119+
private_key: RsaKey,
120+
all_chain_certificate: List[str], ) -> UserCredentialPasswordIp:
121+
session_token = self.installation_context.token
122+
client_key_pair = self.installation_context.private_key_client
123+
124+
string_to_sign = security.public_key_to_string(client_key_pair.publickey()) + session_token
125+
encoded_signature = security.generate_signature(string_to_sign, private_key)
126+
127+
payment_response_provider = PaymentServiceProviderCredentialInternal.create_with_api_context(
128+
certificate,
129+
security.get_certificate_chain_string(all_chain_certificate),
130+
encoded_signature,
131+
self
132+
)
133+
134+
return payment_response_provider
135+
86136
def _register_device(self,
87137
device_description: str,
88138
permitted_ips: List[str]) -> None:

0 commit comments

Comments
 (0)