"""String utility methods.""" import os import re from pathlib import Path from typing import Any from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization def decrypt_rsa_file(path: str | Path, password: bytes | str | None) -> Any: """Load and decrypt an RSA private key from a file. Args: path: Path to the PEM-encoded private key file password: Password to decrypt the key, if encrypted Returns: The loaded private key object """ expanded_path = os.path.expanduser(str(path)) with open(expanded_path, 'rb') as reader: content = reader.read() return decrypt_rsa(content, password) def decrypt_rsa(key_bytes: bytes, password: bytes | str | None) -> Any: """Decrypt an RSA private key from PEM-encoded bytes. Args: key_bytes: PEM-encoded private key bytes password: Password to decrypt the key, if encrypted Returns: The loaded private key object """ if isinstance(password, str): password = password.strip().encode('utf-8') return serialization.load_pem_private_key( key_bytes, password=password, backend=default_backend() ) def encode_der(key: Any) -> bytes: """Encode a private key to DER format. Args: key: Private key object to encode Returns: DER-encoded private key bytes """ return key.private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) def to_snake_case(name: str) -> str: """Convert PascalCase to snake_case and normalize underscores.""" # Replace hyphens with underscores name = name.replace('-', '_') # Convert PascalCase to snake_case s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) result = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() # Collapse multiple underscores into one result = re.sub('_+', '_', result) return result