hippius 0.2.41__tar.gz → 0.2.43__tar.gz

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.
Files changed (23) hide show
  1. {hippius-0.2.41 → hippius-0.2.43}/PKG-INFO +1 -1
  2. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/__init__.py +1 -1
  3. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/client.py +3 -3
  4. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/ipfs.py +86 -18
  5. {hippius-0.2.41 → hippius-0.2.43}/pyproject.toml +1 -1
  6. {hippius-0.2.41 → hippius-0.2.43}/README.md +0 -0
  7. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/cli.py +0 -0
  8. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/cli_assets.py +0 -0
  9. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/cli_handlers.py +0 -0
  10. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/cli_parser.py +0 -0
  11. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/cli_rich.py +0 -0
  12. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/config.py +0 -0
  13. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/db/README.md +0 -0
  14. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/db/env.db.template +0 -0
  15. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/db/migrations/20241201000001_create_key_storage_tables.sql +0 -0
  16. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/db/migrations/20241202000001_switch_to_subaccount_encryption.sql +0 -0
  17. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/db/setup_database.sh +0 -0
  18. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/db_utils.py +0 -0
  19. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/errors.py +0 -0
  20. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/ipfs_core.py +0 -0
  21. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/key_storage.py +0 -0
  22. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/substrate.py +0 -0
  23. {hippius-0.2.41 → hippius-0.2.43}/hippius_sdk/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hippius
3
- Version: 0.2.41
3
+ Version: 0.2.43
4
4
  Summary: Python SDK and CLI for Hippius blockchain storage
5
5
  Home-page: https://github.com/thenervelab/hippius-sdk
6
6
  Author: Dubs
@@ -26,7 +26,7 @@ from hippius_sdk.config import (
26
26
  from hippius_sdk.ipfs import IPFSClient, S3PublishResult, S3DownloadResult
27
27
  from hippius_sdk.utils import format_cid, format_size, hex_to_ipfs_cid
28
28
 
29
- __version__ = "0.2.41"
29
+ __version__ = "0.2.43"
30
30
  __all__ = [
31
31
  "HippiusClient",
32
32
  "IPFSClient",
@@ -600,12 +600,12 @@ class HippiusClient:
600
600
  auto_decrypt: Whether to attempt automatic decryption (default: True)
601
601
  download_node: IPFS node URL for download (default: local node)
602
602
  return_bytes: If True, return bytes instead of saving to file
603
- streaming: If True, return raw streaming iterator from IPFS (no decryption)
603
+ streaming: If True, return decrypted bytes when auto_decrypt=True, or raw streaming iterator when auto_decrypt=False
604
604
 
605
605
  Returns:
606
606
  S3DownloadResult: Download info and decryption status (default)
607
- bytes: Raw decrypted content when return_bytes=True
608
- AsyncIterator[bytes]: Raw streaming iterator when streaming=True
607
+ bytes: Raw decrypted content when return_bytes=True or streaming=True with auto_decrypt=True
608
+ AsyncIterator[bytes]: Raw streaming iterator when streaming=True and auto_decrypt=False
609
609
 
610
610
  Raises:
611
611
  HippiusIPFSError: If IPFS download fails
@@ -69,6 +69,7 @@ class S3PublishPin(BaseModel):
69
69
  cid: str
70
70
  subaccount: str
71
71
  file_path: str
72
+ file_name: str
72
73
  pin_node: str
73
74
  substrate_url: str
74
75
 
@@ -2113,7 +2114,7 @@ class IPFSClient:
2113
2114
  except Exception as e:
2114
2115
  raise HippiusIPFSError(
2115
2116
  f"Failed to upload content to store node {store_node}: {str(e)}"
2116
- )
2117
+ ) from e
2117
2118
 
2118
2119
  # Step 2: Pin to pin_node (remote) for persistence and backup
2119
2120
  try:
@@ -2123,7 +2124,7 @@ class IPFSClient:
2123
2124
  except Exception as e:
2124
2125
  raise HippiusIPFSError(
2125
2126
  f"Failed to pin content to pin node {pin_node}: {str(e)}"
2126
- )
2127
+ ) from e
2127
2128
 
2128
2129
  # Conditionally publish to substrate marketplace based on publish flag
2129
2130
  if publish:
@@ -2166,7 +2167,9 @@ class IPFSClient:
2166
2167
  logger.debug(
2167
2168
  "Possible causes: insufficient credits, network issues, invalid seed phrase, or substrate node unavailability"
2168
2169
  )
2169
- raise HippiusSubstrateError(f"Failed to publish to substrate: {str(e)}")
2170
+ raise HippiusSubstrateError(
2171
+ f"Failed to publish to substrate: {str(e)}"
2172
+ ) from e
2170
2173
 
2171
2174
  return S3PublishResult(
2172
2175
  cid=cid,
@@ -2181,6 +2184,7 @@ class IPFSClient:
2181
2184
  cid=cid,
2182
2185
  subaccount=subaccount_id,
2183
2186
  file_path=filename,
2187
+ file_name=filename,
2184
2188
  pin_node=pin_node,
2185
2189
  substrate_url=substrate_url,
2186
2190
  )
@@ -2202,7 +2206,7 @@ class IPFSClient:
2202
2206
  This method provides multiple output modes:
2203
2207
  1. File output: Downloads to specified path (default mode)
2204
2208
  2. Bytes output: Returns decrypted bytes in memory (return_bytes=True)
2205
- 3. Streaming output: Returns raw streaming iterator from IPFS node (streaming=True)
2209
+ 3. Streaming output: Returns decrypted bytes or raw iterator based on auto_decrypt (streaming=True)
2206
2210
 
2207
2211
  Args:
2208
2212
  cid: Content Identifier (CID) of the file to download
@@ -2212,12 +2216,12 @@ class IPFSClient:
2212
2216
  auto_decrypt: Whether to attempt automatic decryption (default: True)
2213
2217
  download_node: IPFS node URL for download (default: local node)
2214
2218
  return_bytes: If True, return bytes instead of saving to file
2215
- streaming: If True, return raw streaming iterator from IPFS (no decryption)
2219
+ streaming: If True, return decrypted bytes when auto_decrypt=True, or raw streaming iterator when auto_decrypt=False
2216
2220
 
2217
2221
  Returns:
2218
2222
  S3DownloadResult: Download info and decryption status (default)
2219
- bytes: Raw decrypted content when return_bytes=True
2220
- AsyncIterator[bytes]: Raw streaming iterator when streaming=True
2223
+ bytes: Raw decrypted content when return_bytes=True or streaming=True with auto_decrypt=True
2224
+ AsyncIterator[bytes]: Raw streaming iterator when streaming=True and auto_decrypt=False
2221
2225
 
2222
2226
  Raises:
2223
2227
  HippiusIPFSError: If IPFS download fails
@@ -2228,18 +2232,80 @@ class IPFSClient:
2228
2232
  if streaming and return_bytes:
2229
2233
  raise ValueError("Cannot specify both streaming and return_bytes")
2230
2234
 
2231
- if streaming and (auto_decrypt or subaccount_id or bucket_name):
2232
- logger.warning(
2233
- "streaming=True ignores decryption parameters - returns raw encrypted stream"
2234
- )
2235
-
2236
2235
  if streaming:
2237
- # Return raw streaming iterator from IPFS node - no processing
2238
- # _get_ipfs_stream is an async generator, return it directly
2239
- async def streaming_wrapper():
2236
+ # Validate required parameters for decryption if auto_decrypt is True
2237
+ if auto_decrypt and (not subaccount_id or not bucket_name):
2238
+ raise ValueError(
2239
+ "subaccount_id and bucket_name are required for streaming decryption"
2240
+ )
2241
+
2242
+ if auto_decrypt:
2243
+ # Return decrypted bytes directly (not streaming)
2244
+ try:
2245
+ key_storage_available = is_key_storage_enabled()
2246
+ except ImportError:
2247
+ key_storage_available = False
2248
+
2249
+ encryption_key_bytes = None
2250
+
2251
+ if key_storage_available:
2252
+ # Create combined key identifier from account+bucket
2253
+ account_bucket_key = f"{subaccount_id}:{bucket_name}"
2254
+
2255
+ try:
2256
+ existing_key_b64 = await get_key_for_subaccount(
2257
+ account_bucket_key
2258
+ )
2259
+ if existing_key_b64:
2260
+ encryption_key_bytes = base64.b64decode(existing_key_b64)
2261
+ except Exception as e:
2262
+ logger.debug(f"Failed to get encryption key: {e}")
2263
+
2264
+ # If key storage decryption failed or wasn't available, try client encryption key
2265
+ if not encryption_key_bytes and self.encryption_available:
2266
+ logger.debug("Using client encryption key for streaming decryption")
2267
+ encryption_key_bytes = self.encryption_key
2268
+
2269
+ if not encryption_key_bytes:
2270
+ logger.warning(
2271
+ "No encryption key found - downloading raw encrypted data as bytes"
2272
+ )
2273
+ # Return raw encrypted data as bytes
2274
+ encrypted_data = b""
2275
+ async for chunk in self._get_ipfs_stream(cid, download_node):
2276
+ encrypted_data += chunk
2277
+ return encrypted_data
2278
+
2279
+ # Stream and decrypt the content using hybrid buffered approach
2280
+ import nacl.secret
2281
+
2282
+ # Collect all encrypted data first
2283
+ logger.debug("Buffering encrypted content for decryption")
2284
+ encrypted_data = b""
2240
2285
  async for chunk in self._get_ipfs_stream(cid, download_node):
2241
- yield chunk
2242
- return streaming_wrapper()
2286
+ encrypted_data += chunk
2287
+
2288
+ # Decrypt the complete buffered content and return as bytes
2289
+ try:
2290
+ box = nacl.secret.SecretBox(encryption_key_bytes)
2291
+ decrypted_data = box.decrypt(encrypted_data)
2292
+ logger.info(f"Successfully decrypted {len(decrypted_data)} bytes")
2293
+
2294
+ # Return all decrypted data as bytes
2295
+ return decrypted_data
2296
+
2297
+ except Exception as decrypt_error:
2298
+ logger.error(f"Streaming decryption failed: {decrypt_error}")
2299
+ raise ValueError(
2300
+ f"Failed to decrypt streaming content: {decrypt_error}"
2301
+ )
2302
+ else:
2303
+ # Return raw streaming iterator from IPFS node - no processing
2304
+ async def streaming_wrapper():
2305
+ async for chunk in self._get_ipfs_stream(cid, download_node):
2306
+ yield chunk
2307
+
2308
+ return streaming_wrapper()
2243
2309
 
2244
2310
  start_time = time.time()
2245
2311
 
@@ -2256,7 +2322,9 @@ class IPFSClient:
2256
2322
  try:
2257
2323
  # Create parent directories if they don't exist (only for file output mode)
2258
2324
  if not return_bytes:
2259
- os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
2325
+ os.makedirs(
2326
+ os.path.dirname(os.path.abspath(output_path)), exist_ok=True
2327
+ )
2260
2328
 
2261
2329
  download_client = AsyncIPFSClient(api_url=download_node)
2262
2330
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "hippius"
3
- version = "0.2.41"
3
+ version = "0.2.43"
4
4
  description = "Python SDK and CLI for Hippius blockchain storage"
5
5
  authors = ["Dubs <dubs@dubs.rs>"]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes
File without changes