Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions otdf-python-proto/scripts/generate_connect_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def check_dependencies() -> bool:
try:
subprocess.run(check_cmd, shell=True, capture_output=True, check=True)
print(f"✓ {name} is available")
except (subprocess.CalledProcessError, FileNotFoundError):
except (subprocess.CalledProcessError, FileNotFoundError): # noqa: PERF203
missing.append(name)
print(f"✗ {name} is missing")

Expand Down Expand Up @@ -104,7 +104,7 @@ def copy_opentdf_proto_files(proto_gen_dir: Path) -> bool:

copied_files += 1

except Exception as e:
except Exception as e: # noqa: PERF203
print(f" Warning: Failed to copy {relative_path}: {e}")

print(f"Found and copied {copied_files} proto files from repository")
Expand Down Expand Up @@ -235,7 +235,7 @@ def _fix_ignore_if_default_value(proto_files_dir):

print(f"Updated {proto_file.name} to use IGNORE_IF_ZERO_VALUE")

except Exception as e:
except Exception as e: # noqa: PERF203
print(f"Error updating {proto_file.name}: {e}")


Expand Down
9 changes: 2 additions & 7 deletions src/otdf_python/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
OpenTDF Python CLI

A command-line interface for encrypting and decrypting files using OpenTDF.
Provides encrypt, decrypt, and inspect commands similar to the TypeScript CLI.
Provides encrypt, decrypt, and inspect commands similar to the otdfctl CLI.
"""

import argparse
Expand Down Expand Up @@ -146,7 +146,7 @@ def build_sdk(args) -> SDK:
else:
raise CLIError(
"CRITICAL",
"Authentication required: provide --with-client-creds-file, --client-id and --client-secret, or --auth",
"Authentication required: provide --with-client-creds-file OR --client-id and --client-secret",
)

if hasattr(args, "plaintext") and args.plaintext:
Expand Down Expand Up @@ -479,11 +479,6 @@ def create_parser() -> argparse.ArgumentParser:
)
auth_group.add_argument("--client-id", help="OAuth client ID")
auth_group.add_argument("--client-secret", help="OAuth client secret")
# Keep --auth for backward compatibility
auth_group.add_argument(
"--auth",
help="Combined OAuth credentials (clientId:clientSecret) - deprecated, use --with-client-creds-file",
)

# Security options
security_group = parser.add_argument_group("Security")
Expand Down
5 changes: 0 additions & 5 deletions src/otdf_python/crypto_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,3 @@ def get_rsa_private_key_from_pem(pem_data: str) -> rsa.RSAPrivateKey:
if not isinstance(private_key, rsa.RSAPrivateKey):
raise ValueError("Not an RSA private key")
return private_key


# Aliases for compatibility
rsa_private_key_from_pem = CryptoUtils.get_rsa_private_key_from_pem
rsa_public_key_from_pem = CryptoUtils.get_rsa_public_key_from_pem
15 changes: 8 additions & 7 deletions src/otdf_python/kas_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,11 @@ def _handle_existing_scheme(self, parsed) -> str:
def _create_signed_request_jwt(self, policy_json, client_public_key, key_access): # noqa: C901
"""
Create a signed JWT for the rewrap request.
The JWT is signed with the DPoP private key, matching Java SDK implementation exactly.
The JWT is signed with the DPoP private key, mimicking the Java SDK implementation.
"""
# Convert the KeyAccess to a dict that matches Java SDK structure
# Handle both ManifestKeyAccess (new camelCase and old snake_case) and simple KeyAccess (for tests)
# TODO: This can probably be simplified to only camelCase

# Ensure wrappedKey is a base64-encoded string
# Note: wrappedKey from manifest is already base64-encoded
Expand Down Expand Up @@ -248,8 +249,8 @@ def _create_signed_request_jwt(self, policy_json, client_public_key, key_access)
},
}
],
"keyAccess": key_access_dict, # Keep legacy field for backward compatibility
"policy": policy_base64, # Keep legacy field for backward compatibility
"keyAccess": key_access_dict,
"policy": policy_base64,
}

# Convert to JSON string
Expand Down Expand Up @@ -532,7 +533,7 @@ def _parse_and_decrypt_response(self, response):
encrypted_key = b64decode(entity_wrapped_key)
return self.decryptor.decrypt(encrypted_key)

def unwrap(self, key_access, policy_json, session_key_type=None):
def unwrap(self, key_access, policy_json, session_key_type=None) -> bytes:
"""
Unwrap a key using Connect RPC.

Expand All @@ -544,7 +545,7 @@ def unwrap(self, key_access, policy_json, session_key_type=None):
Returns:
Unwrapped key bytes
"""
# Default to RSA if not specified (for backward compatibility)
# Default to RSA if not specified
if session_key_type is None:
session_key_type = RSA_KEY_TYPE

Expand All @@ -561,9 +562,9 @@ def unwrap(self, key_access, policy_json, session_key_type=None):
)

# Call Connect RPC unwrap
return self._unwrap_with_connect_rpc(key_access, signed_token, policy_json)
return self._unwrap_with_connect_rpc(key_access, signed_token)

def _unwrap_with_connect_rpc(self, key_access, signed_token, policy_json):
def _unwrap_with_connect_rpc(self, key_access, signed_token) -> bytes:
"""
Connect RPC method for unwrapping keys.
"""
Expand Down
6 changes: 4 additions & 2 deletions src/otdf_python/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ def _root_sig(rs):
return ManifestRootSignature(**rs)

def _integrity(i):
# Handle both old snake_case and new camelCase formats for backward compatibility
# Handle both snake_case and camelCase fields
# TODO: This can probably be simplified to only camelCase
return ManifestIntegrityInformation(
rootSignature=_root_sig(
i.get("rootSignature", i.get("root_signature"))
Expand All @@ -174,7 +175,8 @@ def _key_access(k):
return ManifestKeyAccess(**k)

def _enc_info(e):
# Handle both old snake_case and new camelCase formats
# Handle both snake_case and camelCase fields
# TODO: This can probably be simplified to only camelCase
return ManifestEncryptionInformation(
type=e.get("type", e.get("key_access_type", "split")),
policy=e["policy"],
Expand Down
7 changes: 3 additions & 4 deletions src/otdf_python/nanotdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,10 @@ def read_nano_tdf(
if not kas_private_key and not kas_mock_unwrap:
raise InvalidNanoTDFConfig("Missing kas_private_key for unwrap.")
if kas_mock_unwrap:
# Use the SDK.KAS mock unwrap_nanotdf logic
from otdf_python.sdk import SDK
# Use the KAS mock unwrap_nanotdf logic
from otdf_python.sdk import KAS

key = SDK.KAS().unwrap_nanotdf(
key = KAS().unwrap_nanotdf(
curve=None,
header=None,
kas_url=None,
Expand All @@ -395,7 +395,6 @@ def read_nano_tdf(
plaintext = aesgcm.decrypt(iv_padded, ciphertext, None)
output_stream.write(plaintext)

# Legacy method names for backward compatibility
def _convert_dict_to_nanotdf_config(self, config: dict) -> NanoTDFConfig:
"""Convert a dictionary config to a NanoTDFConfig object."""
converted_config = NanoTDFConfig()
Expand Down
Loading
Loading