otdf-python 0.6.0__py3-none-any.whl → 0.7.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,7 @@ from dataclasses import dataclass
6
6
  @dataclass
7
7
  class AuthHeaders:
8
8
  """Represents authentication headers used in token-based authorization.
9
+
9
10
  This class holds authorization and DPoP (Demonstrating Proof of Possession) headers
10
11
  that are used in token-based API requests.
11
12
  """
otdf_python/kas_client.py CHANGED
@@ -362,6 +362,7 @@ class KASClient:
362
362
  self, policy_json, client_public_key, key_access, session_key_type=None
363
363
  ):
364
364
  """Create a signed JWT for the rewrap request.
365
+
365
366
  The JWT is signed with the DPoP private key.
366
367
 
367
368
  Args:
@@ -400,6 +401,7 @@ class KASClient:
400
401
 
401
402
  def _create_connect_rpc_signed_token(self, key_access, policy_json):
402
403
  """Create a signed token specifically for Connect RPC requests.
404
+
403
405
  For now, this delegates to the existing JWT creation method.
404
406
  """
405
407
  return self._create_signed_request_jwt(
@@ -469,6 +471,7 @@ class KASClient:
469
471
 
470
472
  def get_public_key(self, kas_info):
471
473
  """Get KAS public key using Connect RPC.
474
+
472
475
  Checks cache first if available.
473
476
  """
474
477
  try:
@@ -569,6 +572,7 @@ class KASClient:
569
572
 
570
573
  def _prepare_rsa_keypair(self):
571
574
  """Prepare RSA key pair for unwrapping, reusing if possible.
575
+
572
576
  Uses separate ephemeral keys for encryption (not DPoP keys).
573
577
 
574
578
  Returns:
@@ -1,10 +1,11 @@
1
1
  """KASConnectRPCClient: Handles Connect RPC communication with the Key Access Service (KAS).
2
+
2
3
  This class encapsulates all interactions with otdf_python_proto.
3
4
  """
4
5
 
5
6
  import logging
6
7
 
7
- import httpx
8
+ import pyqwest
8
9
  from otdf_python_proto.kas import kas_pb2
9
10
  from otdf_python_proto.kas.kas_connect import AccessServiceClientSync
10
11
 
@@ -26,6 +27,7 @@ class KASConnectRPCClient:
26
27
  """
27
28
  self.use_plaintext = use_plaintext
28
29
  self.verify_ssl = verify_ssl
30
+ self._transport = None
29
31
  self._http_client = None
30
32
 
31
33
  def __enter__(self):
@@ -38,35 +40,41 @@ class KASConnectRPCClient:
38
40
  self.close()
39
41
 
40
42
  def close(self):
41
- """Close HTTP client and release resources.
42
-
43
- This method should be called when the client is no longer needed
44
- to properly clean up resources. It's also called automatically
45
- when using the client as a context manager.
46
- """
47
- if self._http_client is not None:
48
- self._http_client.close()
49
- self._http_client = None
43
+ """Close HTTP client and release resources."""
44
+ if self._transport is not None:
45
+ self._transport.close()
46
+ self._transport = None
47
+ self._http_client = None
50
48
 
51
49
  def _create_http_client(self):
52
- """Create HTTP client with SSL verification configuration.
50
+ """Create HTTP client backed by a pyqwest.SyncHTTPTransport.
51
+
52
+ Supports plaintext (HTTP) and TLS (HTTPS) connections.
53
+ Custom CA/cert data is not yet supported.
53
54
 
54
55
  Returns:
55
- httpx.Client configured for SSL verification settings
56
+ pyqwest.SyncClient configured for the current settings
57
+
58
+ Raises:
59
+ NotImplementedError: If verify_ssl=False is requested, as pyqwest
60
+ does not support disabling TLS verification. Passing custom
61
+ TLS certificate or CA data is also not yet implemented.
56
62
 
57
63
  """
58
- if self.verify_ssl:
59
- logging.info("Using SSL verification enabled HTTP client")
60
- return httpx.Client()
61
- else:
62
- logging.info("Using SSL verification disabled HTTP client")
63
- return httpx.Client(verify=False)
64
+ if not self.verify_ssl and not self.use_plaintext:
65
+ raise NotImplementedError(
66
+ "verify_ssl=False is not supported for HTTPS connections: pyqwest "
67
+ "does not expose an option to disable TLS verification. Passing "
68
+ "custom TLS cert or CA data is also not yet implemented."
69
+ )
70
+ self._transport = pyqwest.SyncHTTPTransport()
71
+ return pyqwest.SyncClient(transport=self._transport)
64
72
 
65
73
  def _get_http_client(self):
66
74
  """Get HTTP client, creating one if needed for backward compatibility.
67
75
 
68
76
  Returns:
69
- httpx.Client instance
77
+ pyqwest.SyncClient instance
70
78
 
71
79
  """
72
80
  if self._http_client is None:
@@ -136,12 +144,9 @@ class KASConnectRPCClient:
136
144
  f"for public key retrieval"
137
145
  )
138
146
 
139
- # Get or create HTTP client
140
147
  http_client = self._get_http_client()
141
-
142
- # Create Connect RPC client with configured HTTP client
143
148
  client = AccessServiceClientSync(
144
- address=connect_rpc_base_url, session=http_client
149
+ address=connect_rpc_base_url, http_client=http_client
145
150
  )
146
151
 
147
152
  # Create public key request
@@ -202,12 +207,9 @@ class KASConnectRPCClient:
202
207
  f"Creating Connect RPC client for base URL: {kas_service_url}, for unwrap"
203
208
  )
204
209
 
205
- # Get or create HTTP client
206
210
  http_client = self._get_http_client()
207
-
208
- # Create Connect RPC client with configured HTTP client
209
211
  client = AccessServiceClientSync(
210
- address=kas_service_url, session=http_client
212
+ address=kas_service_url, http_client=http_client
211
213
  )
212
214
 
213
215
  # Create rewrap request
@@ -215,7 +217,6 @@ class KASConnectRPCClient:
215
217
  signed_request_token=signed_token,
216
218
  )
217
219
 
218
- # Debug: Log the signed token details
219
220
  logging.info(f"Connect RPC signed token: {signed_token}")
220
221
 
221
222
  # Prepare headers with authentication if available
otdf_python/kas_info.py CHANGED
@@ -6,6 +6,7 @@ from dataclasses import dataclass
6
6
  @dataclass
7
7
  class KASInfo:
8
8
  """Configuration for Key Access Server (KAS) information.
9
+
9
10
  This class stores details about a Key Access Server including its URL,
10
11
  public key, key ID, default status, and cryptographic algorithm.
11
12
  """
@@ -1,4 +1,5 @@
1
1
  """Constants for session key types used in the KAS client.
2
+
2
3
  This matches the Java SDK's KeyType enum pattern.
3
4
  """
4
5
 
@@ -68,6 +68,7 @@ class NanoTDFECDSAStruct:
68
68
 
69
69
  def as_bytes(self) -> bytes:
70
70
  """Convert the signature structure to bytes.
71
+
71
72
  Raises ValueError if r_value or s_value is None.
72
73
  """
73
74
  if self.r_value is None or self.s_value is None:
@@ -18,6 +18,7 @@ class PolicyBinding:
18
18
 
19
19
  class PolicyBindingSerializer:
20
20
  """Handles serialization and deserialization of policy bindings.
21
+
21
22
  This class provides static methods to convert between JSON representations
22
23
  and PolicyBinding objects.
23
24
  """
otdf_python/sdk.py CHANGED
@@ -15,6 +15,7 @@ class KAS(AbstractContextManager):
15
15
 
16
16
  def get_public_key(self, kas_info: Any) -> Any:
17
17
  """Retrieve the public key from KAS for RSA operations.
18
+
18
19
  If the public key is cached, returns the cached value.
19
20
  Otherwise, makes a request to the KAS.
20
21
 
@@ -217,6 +218,7 @@ class SDK(AbstractContextManager):
217
218
 
218
219
  def kas(self) -> KAS:
219
220
  """Return the KAS client for key access operations.
221
+
220
222
  This should be implemented to return an instance of KAS.
221
223
  """
222
224
  raise NotImplementedError
@@ -8,7 +8,7 @@ import ssl
8
8
  from dataclasses import dataclass
9
9
  from pathlib import Path
10
10
 
11
- import httpx
11
+ import httpx2 as httpx
12
12
 
13
13
  from otdf_python.kas_allowlist import KASAllowlist
14
14
  from otdf_python.sdk import KAS, SDK
otdf_python/tdf_reader.py CHANGED
@@ -12,6 +12,7 @@ TDF_PAYLOAD_FILE_NAME = "0.payload"
12
12
 
13
13
  class TDFReader:
14
14
  """TDFReader is responsible for reading and processing Trusted Data Format (TDF) files.
15
+
15
16
  The class initializes with a TDF file channel, extracts the manifest and payload entries,
16
17
  and provides methods to retrieve the manifest content, read payload bytes, and read policy objects.
17
18
  """
@@ -2,7 +2,7 @@
2
2
 
3
3
  import time
4
4
 
5
- import httpx
5
+ import httpx2 as httpx
6
6
 
7
7
 
8
8
  class TokenSource:
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: otdf-python
3
- Version: 0.6.0
3
+ Version: 0.7.3
4
4
  Summary: Unofficial OpenTDF SDK for Python
5
5
  Project-URL: Homepage, https://github.com/b-long/opentdf-python-sdk
6
6
  Project-URL: Repository, https://github.com/b-long/opentdf-python-sdk
7
7
  Project-URL: Issues, https://github.com/b-long/opentdf-python-sdk/issues
8
8
  Author-email: b-long <b-long@users.noreply.github.com>
9
- License-File: LICENSE
10
9
  Classifier: Development Status :: 4 - Beta
11
10
  Classifier: Intended Audience :: Developers
12
11
  Classifier: License :: OSI Approved :: MIT License
@@ -22,15 +21,12 @@ Classifier: Topic :: Security :: Cryptography
22
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
22
  Classifier: Typing :: Typed
24
23
  Requires-Python: >=3.10
25
- Requires-Dist: connect-python<0.7,>=0.6.0
24
+ Requires-Dist: connect-python>=0.9.0
26
25
  Requires-Dist: cryptography>=45.0.4
27
26
  Requires-Dist: grpcio-status>=1.74.0
28
- Requires-Dist: grpcio-tools>=1.74.0
29
27
  Requires-Dist: grpcio>=1.74.0
30
- Requires-Dist: httpx>=0.28.1
28
+ Requires-Dist: httpx2>=2.3.0
31
29
  Requires-Dist: protobuf>=6.31.1
32
- Requires-Dist: protoc-gen-connect-python<0.7,>=0.6.0
33
- Requires-Dist: protoc-gen-openapiv2>=0.0.1
34
30
  Requires-Dist: pyjwt>=2.10.1
35
31
  Requires-Dist: typing-extensions>=4.14.1
36
32
  Description-Content-Type: text/markdown
@@ -137,7 +133,7 @@ with open("decrypted.txt", "wb") as f:
137
133
  ## Project Structure
138
134
 
139
135
  ```
140
- src/otdf_python/
136
+ packages/otdf-python/src/otdf_python/
141
137
  ├── sdk.py # Main SDK interface
142
138
  ├── config.py # Configuration management
143
139
  ├── tdf.py # TDF format handling
@@ -4,7 +4,7 @@ otdf_python/address_normalizer.py,sha256=7gigfxFIFnDILi8BGQipuLl-Cr71pwi5vE72hbp
4
4
  otdf_python/aesgcm.py,sha256=jQgVSEeKM6MJuH2tvlClXIzvg11a5O_GEY9Sh56CrxE,1947
5
5
  otdf_python/assertion_config.py,sha256=rw0SIB3xG-nAeb5r_liuxLphU4tcj-zlq8rVvXncX-Y,2317
6
6
  otdf_python/asym_crypto.py,sha256=EYkMNhZJP5khH0IvICTOG2bMg_TMvd6wXDu5zW0jpj4,7234
7
- otdf_python/auth_headers.py,sha256=uOLflFunBCw59nwk23rdiFQWOFrS19HugQXuQPGv3xE,986
7
+ otdf_python/auth_headers.py,sha256=onS-fXsIZN4l33yQS9VspPvoiAnfM2B0nNAVL_YIGZ0,987
8
8
  otdf_python/autoconfigure_utils.py,sha256=W5aJ0tC7HWfGb_1Mva_oxgduUzSpPoyDeaq0rPwgPAs,3689
9
9
  otdf_python/cli.py,sha256=icooiGgRh8H1IlP-_iO7paLB60IXUSaSacODABeqrS4,21165
10
10
  otdf_python/collection_store.py,sha256=sYL6VMFDBfHfCCLk14iybeC_qoUlpJFB0wOMt1bdwpY,1429
@@ -21,29 +21,29 @@ otdf_python/eckeypair.py,sha256=qcPKv0OS1lYxRICj9dhAW_eMz32anFBtpI8EJfXxpX0,2470
21
21
  otdf_python/header.py,sha256=peG14kE_KAUCW4fY82sqcWF5zTAVAnJfFXCHtC8Z0iQ,7189
22
22
  otdf_python/invalid_zip_exception.py,sha256=M_bAiXEjJdxPfA178YH-uHGRwMrNBKzjQzlQ54aDP2w,292
23
23
  otdf_python/kas_allowlist.py,sha256=0yX3J9J1od_ew0sp3pX6kfav39pTz7aBBpMnVkE5T7s,5884
24
- otdf_python/kas_client.py,sha256=N5mQubRUrnJCtSxTiiyjf7DEfsg2wVZ02xufuZBH_b0,27532
25
- otdf_python/kas_connect_rpc_client.py,sha256=cB3cBomCClmu-InUpw8R35cLyJQ8X0PoEsFvYSH0RUM,8950
26
- otdf_python/kas_info.py,sha256=V-5om8k4RKbhE0h1CS1Rxb18TYcHKvq_hEPP6ah8K_o,738
24
+ otdf_python/kas_client.py,sha256=kcLpdkFDN3LVmlmSuaEm6EKtPsbOK5RCsClPdm8bpAU,27536
25
+ otdf_python/kas_connect_rpc_client.py,sha256=Y2w0SPh4QZxLLhneKky8N20jd9UQmShmAnLo_c9kOXk,9113
26
+ otdf_python/kas_info.py,sha256=R_zfW8m2n2PT1-Enk6NG5K8YIjWvb1g-PQ6M0bZX-o8,739
27
27
  otdf_python/kas_key_cache.py,sha256=6hfzRAg9o_IfRErWSe-_gGTG9kRyYENMizMY1Shkmfk,1548
28
28
  otdf_python/key_type.py,sha256=2gQlXOj35J3ISCcWjU3sGYUxmlZR47BMq6Xr2yoKA8k,928
29
- otdf_python/key_type_constants.py,sha256=MV2Dsea3A6nnnYztoD0N1QxhrbQXZfaXaqCr2rI6sqo,954
29
+ otdf_python/key_type_constants.py,sha256=0aqG1N1Ay0Z8o5fsq7fAiJXQeD6k-fxp06If__BGcR4,955
30
30
  otdf_python/manifest.py,sha256=aglGw9EdtZZIxmwqy82sV5wum_mKkjzew4brSgxmJjc,7047
31
31
  otdf_python/nanotdf.py,sha256=y1mLktlZ-mRCup2vzGY4ZbFeNEhWpCYLOZYjzTSPEtc,33921
32
- otdf_python/nanotdf_ecdsa_struct.py,sha256=jTQKFAicTfMfN9CxJZYQcnEYGmtfAQoDOhz8ta-pGAQ,4066
32
+ otdf_python/nanotdf_ecdsa_struct.py,sha256=C-qQnroJGO9yXrBb-p-rYMSxf2gS8kF6SCUvO-njAXU,4067
33
33
  otdf_python/nanotdf_type.py,sha256=3MQzT6lJ3WJKMICFyyYZXX2_cFYcZ5G4m1uif-l9Nxo,1112
34
- otdf_python/policy_binding_serializer.py,sha256=oOcGBYOISPTzHRtk8JszwLTraY_F2OoevOf0a53jGHA,1271
34
+ otdf_python/policy_binding_serializer.py,sha256=hA-M5BhEa3Q0bpjbpdiaJ6mivwx9UGDdmB8HvFG7SY0,1272
35
35
  otdf_python/policy_info.py,sha256=aq74dZg9PhTZ6cMkZyFsu3D754C5YijFMiuoYEL-1bY,2076
36
36
  otdf_python/policy_object.py,sha256=LikIsahPkKr-iYA0lhgQitCbh8CsmxUBYyBs6VYfmxY,512
37
37
  otdf_python/policy_stub.py,sha256=RfU_fICqsAOnTXOHpKhtKC0RJ3KoWhDxO0XecZWM548,159
38
38
  otdf_python/resource_locator.py,sha256=bjK935XcfNq-PyqidHNq8eIiPeZEStYdQvmQ9B9GY20,6290
39
- otdf_python/sdk.py,sha256=-3Zuyfvf8ZM6iqxFpFDRAxCSfe35r6-TIuOOGUbPNPM,15058
40
- otdf_python/sdk_builder.py,sha256=xTPoBjB3eGwoWjfSgiPmiNnEZJ8g-LUQVZDmo7BM9cY,17649
39
+ otdf_python/sdk.py,sha256=6yQbaHS6EUqiEOEn2hI3Ox4OYlYQHDuxjqHjYo8LV5A,15060
40
+ otdf_python/sdk_builder.py,sha256=N57HrXADKLSP3bGiltYV058DxgrJyMzhsKuqNuKBqqo,17659
41
41
  otdf_python/sdk_exceptions.py,sha256=2GElGyM5LKN8Uh_lAiT6Ho4oNRWYRQsMNOK5s2jiv28,687
42
42
  otdf_python/symmetric_and_payload_config.py,sha256=iPHeZSeY9BjsQ-wkvdm6-FIR7773EgGiaIvSG-ICOHw,1158
43
43
  otdf_python/tdf.py,sha256=lqaSSGfd-nzlmjpYoXa6ZLihZIJA170dwodKt_iRko8,20799
44
- otdf_python/tdf_reader.py,sha256=WMetzX4CIKJ15f4J_zyFGtObQO6bQ33KC_ykIonH9ik,5228
44
+ otdf_python/tdf_reader.py,sha256=f-LCb_Z4TwaByT8_gu-cpJIdW8lk3741jCAd-fJOLJg,5229
45
45
  otdf_python/tdf_writer.py,sha256=FLm1P26J4p6WPyKsjOb7QLYJqDIMDsBONqBW_JuFxyw,798
46
- otdf_python/token_source.py,sha256=YHbP7deSSXo1CvzVGJX7DkOuBgqwfP_Ockm8CE-MN0o,1011
46
+ otdf_python/token_source.py,sha256=Ow4bZqPqVxbZx64M7pLxQarVlPfiz15ZvZr9H17_ZMY,1021
47
47
  otdf_python/version.py,sha256=uDKJKsSQoaEH-JlqAwiXDxceLRX9hkG4I3NVLEfDCHA,2025
48
48
  otdf_python/zip_reader.py,sha256=qrHv-ecs09tz99ZKdOMiWaciYf2XsQOUTiXy1JHjuEY,1705
49
49
  otdf_python/zip_writer.py,sha256=5-KChgEXCf4TKAAML-R8cqpAiap85ur1l2lJCCac6BE,2405
@@ -170,7 +170,6 @@ otdf_python_proto/wellknownconfiguration/__init__.py,sha256=xK8XUrwCL9elWuMTx6vV
170
170
  otdf_python_proto/wellknownconfiguration/wellknown_configuration_connect.py,sha256=wnfZ7K9vAB_Rub25KrdnKIfx5Yxq8yCc8c6zHjBtFH8,6358
171
171
  otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.py,sha256=g9xSm9TxX0IPMqiFCaridJvI2TrL8PrXVFPgu8tX9VM,3863
172
172
  otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.pyi,sha256=Zw4vROvTgomnFqsalJrYda632ojXH0FVXSzTXxerybw,1490
173
- otdf_python-0.6.0.dist-info/METADATA,sha256=WviQsEtDOr5SAG3xyE3vAmbwUTr9YWgYuayXjhrusCo,5175
174
- otdf_python-0.6.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
175
- otdf_python-0.6.0.dist-info/licenses/LICENSE,sha256=DPrPHdI6tfZcqk9kzQ37vh1Ftk7LJYdMrUtwKl7L3Pw,1074
176
- otdf_python-0.6.0.dist-info/RECORD,,
173
+ otdf_python-0.7.3.dist-info/METADATA,sha256=sg8YiLbazn2CqAfjLSApxd6P3UsjGEswjHr4FTcJDd8,5037
174
+ otdf_python-0.7.3.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
175
+ otdf_python-0.7.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.29.0
2
+ Generator: hatchling 1.30.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 to present b-long
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.