hippius 0.2.41__py3-none-any.whl → 0.2.42__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hippius
3
- Version: 0.2.41
3
+ Version: 0.2.42
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
@@ -1,10 +1,10 @@
1
- hippius_sdk/__init__.py,sha256=0Xf8Fnc93-TuSh6wLqELTb2OV2h1tfOmTnMDfe4i2RM,1474
1
+ hippius_sdk/__init__.py,sha256=69XR6atYPkJPYLkUd6NHE15X_4eNNnaKQAy9yIGA4dc,1474
2
2
  hippius_sdk/cli.py,sha256=aqKOYSBSWt7UhcpFt7wf9yIPJ3bznpsJ6ehOnuZ4usI,18235
3
3
  hippius_sdk/cli_assets.py,sha256=rjH3Z5A1CQr2d5CIAAAb0WMCjoZZlMWcdo0f93KqluE,635
4
4
  hippius_sdk/cli_handlers.py,sha256=HkZldE8ZDS6WHu8aSoeS_rYZ4kp3F-Kdzu-weY1c0vU,128258
5
5
  hippius_sdk/cli_parser.py,sha256=z7UvgWvvy04ey-R56qZiCqYc_9RaNq1rVDkQyXoK3JU,21100
6
6
  hippius_sdk/cli_rich.py,sha256=_jTBYMdHi2--fIVwoeNi-EtkdOb6Zy_O2TUiGvU3O7s,7324
7
- hippius_sdk/client.py,sha256=n7QwLneWZym_eKN1fEAJWEi98nSJjdSpZJeEcFjZsqQ,24197
7
+ hippius_sdk/client.py,sha256=6W50r7-WcMyZNI1j3NOKMpcSMlB819AMKM9w06YqMx0,24302
8
8
  hippius_sdk/config.py,sha256=Hf_aUYzG9ylzqauA_ABUSSB5mBTYbp-VtB36VQt2XDw,21981
9
9
  hippius_sdk/db/README.md,sha256=okDeI1qgkaZqXSlJ8L0xIE4UpuxO-qEGPIbXUvSHQjU,2030
10
10
  hippius_sdk/db/env.db.template,sha256=_6hEC3IvkzCDOAzG1_yJUKRUfCTMciNaJUicZpMCat4,217
@@ -13,12 +13,12 @@ hippius_sdk/db/migrations/20241202000001_switch_to_subaccount_encryption.sql,sha
13
13
  hippius_sdk/db/setup_database.sh,sha256=STp03qxkp2RmIVr6YZIcvQQm-_LLUOb6Jobh-52HWmg,3115
14
14
  hippius_sdk/db_utils.py,sha256=-x0rbN0as7Tn3PJPZBYCgreZe52FLH40ppA1TLxsg90,1851
15
15
  hippius_sdk/errors.py,sha256=LScJJmawVAx7aRzqqQguYSkf9iazSjEQEBNlD_GXZ6Y,1589
16
- hippius_sdk/ipfs.py,sha256=uBqjXzF8chKoFcyx9Jmuw9XCINf9qJ3Os1UBPdBsucc,100667
16
+ hippius_sdk/ipfs.py,sha256=CpVSEKVrHrZAXrhJsCPPZcADSx2tpE_ktA1TLlMiUQc,103749
17
17
  hippius_sdk/ipfs_core.py,sha256=WG7bGLk-threOvmumizwh1dnd5zqbIkTXy1y-BRGayI,12789
18
18
  hippius_sdk/key_storage.py,sha256=SXFd6aGQw9MDLGX2vSBuAY7rdX-k5EvFm63z7_n-8yQ,8148
19
19
  hippius_sdk/substrate.py,sha256=4a7UIE4UqGcDW7luKTBgSDqfb2OIZusB39G1UiRs_YU,50158
20
20
  hippius_sdk/utils.py,sha256=rJ611yvwKSyiBpYU3w-SuyQxoghMGU-ePuslrPv5H5g,7388
21
- hippius-0.2.41.dist-info/METADATA,sha256=SSSssIaVQf94BZRTCMotY-zQGwUuByoPwA6svR7ufQE,30088
22
- hippius-0.2.41.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
23
- hippius-0.2.41.dist-info/entry_points.txt,sha256=bFAZjW3vndretf9-8s587jA2ebMVI7puhn_lVs8jPc8,149
24
- hippius-0.2.41.dist-info/RECORD,,
21
+ hippius-0.2.42.dist-info/METADATA,sha256=kSv4QdslPlxwgECpO3_UAq8-CAQGhtK8JEZ-zi7xKgU,30088
22
+ hippius-0.2.42.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
23
+ hippius-0.2.42.dist-info/entry_points.txt,sha256=bFAZjW3vndretf9-8s587jA2ebMVI7puhn_lVs8jPc8,149
24
+ hippius-0.2.42.dist-info/RECORD,,
hippius_sdk/__init__.py CHANGED
@@ -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.42"
30
30
  __all__ = [
31
31
  "HippiusClient",
32
32
  "IPFSClient",
hippius_sdk/client.py CHANGED
@@ -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
hippius_sdk/ipfs.py CHANGED
@@ -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
 
@@ -2181,6 +2182,7 @@ class IPFSClient:
2181
2182
  cid=cid,
2182
2183
  subaccount=subaccount_id,
2183
2184
  file_path=filename,
2185
+ file_name=filename,
2184
2186
  pin_node=pin_node,
2185
2187
  substrate_url=substrate_url,
2186
2188
  )
@@ -2202,7 +2204,7 @@ class IPFSClient:
2202
2204
  This method provides multiple output modes:
2203
2205
  1. File output: Downloads to specified path (default mode)
2204
2206
  2. Bytes output: Returns decrypted bytes in memory (return_bytes=True)
2205
- 3. Streaming output: Returns raw streaming iterator from IPFS node (streaming=True)
2207
+ 3. Streaming output: Returns decrypted bytes or raw iterator based on auto_decrypt (streaming=True)
2206
2208
 
2207
2209
  Args:
2208
2210
  cid: Content Identifier (CID) of the file to download
@@ -2212,12 +2214,12 @@ class IPFSClient:
2212
2214
  auto_decrypt: Whether to attempt automatic decryption (default: True)
2213
2215
  download_node: IPFS node URL for download (default: local node)
2214
2216
  return_bytes: If True, return bytes instead of saving to file
2215
- streaming: If True, return raw streaming iterator from IPFS (no decryption)
2217
+ streaming: If True, return decrypted bytes when auto_decrypt=True, or raw streaming iterator when auto_decrypt=False
2216
2218
 
2217
2219
  Returns:
2218
2220
  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
2221
+ bytes: Raw decrypted content when return_bytes=True or streaming=True with auto_decrypt=True
2222
+ AsyncIterator[bytes]: Raw streaming iterator when streaming=True and auto_decrypt=False
2221
2223
 
2222
2224
  Raises:
2223
2225
  HippiusIPFSError: If IPFS download fails
@@ -2228,18 +2230,80 @@ class IPFSClient:
2228
2230
  if streaming and return_bytes:
2229
2231
  raise ValueError("Cannot specify both streaming and return_bytes")
2230
2232
 
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
2233
  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():
2234
+ # Validate required parameters for decryption if auto_decrypt is True
2235
+ if auto_decrypt and (not subaccount_id or not bucket_name):
2236
+ raise ValueError(
2237
+ "subaccount_id and bucket_name are required for streaming decryption"
2238
+ )
2239
+
2240
+ if auto_decrypt:
2241
+ # Return decrypted bytes directly (not streaming)
2242
+ try:
2243
+ key_storage_available = is_key_storage_enabled()
2244
+ except ImportError:
2245
+ key_storage_available = False
2246
+
2247
+ encryption_key_bytes = None
2248
+
2249
+ if key_storage_available:
2250
+ # Create combined key identifier from account+bucket
2251
+ account_bucket_key = f"{subaccount_id}:{bucket_name}"
2252
+
2253
+ try:
2254
+ existing_key_b64 = await get_key_for_subaccount(
2255
+ account_bucket_key
2256
+ )
2257
+ if existing_key_b64:
2258
+ encryption_key_bytes = base64.b64decode(existing_key_b64)
2259
+ except Exception as e:
2260
+ logger.debug(f"Failed to get encryption key: {e}")
2261
+
2262
+ # If key storage decryption failed or wasn't available, try client encryption key
2263
+ if not encryption_key_bytes and self.encryption_available:
2264
+ logger.debug("Using client encryption key for streaming decryption")
2265
+ encryption_key_bytes = self.encryption_key
2266
+
2267
+ if not encryption_key_bytes:
2268
+ logger.warning(
2269
+ "No encryption key found - downloading raw encrypted data as bytes"
2270
+ )
2271
+ # Return raw encrypted data as bytes
2272
+ encrypted_data = b""
2273
+ async for chunk in self._get_ipfs_stream(cid, download_node):
2274
+ encrypted_data += chunk
2275
+ return encrypted_data
2276
+
2277
+ # Stream and decrypt the content using hybrid buffered approach
2278
+ import nacl.secret
2279
+
2280
+ # Collect all encrypted data first
2281
+ logger.debug("Buffering encrypted content for decryption")
2282
+ encrypted_data = b""
2240
2283
  async for chunk in self._get_ipfs_stream(cid, download_node):
2241
- yield chunk
2242
- return streaming_wrapper()
2284
+ encrypted_data += chunk
2285
+
2286
+ # Decrypt the complete buffered content and return as bytes
2287
+ try:
2288
+ box = nacl.secret.SecretBox(encryption_key_bytes)
2289
+ decrypted_data = box.decrypt(encrypted_data)
2290
+ logger.info(f"Successfully decrypted {len(decrypted_data)} bytes")
2291
+
2292
+ # Return all decrypted data as bytes
2293
+ return decrypted_data
2294
+
2295
+ except Exception as decrypt_error:
2296
+ logger.error(f"Streaming decryption failed: {decrypt_error}")
2297
+ raise ValueError(
2298
+ f"Failed to decrypt streaming content: {decrypt_error}"
2299
+ )
2300
+ else:
2301
+ # Return raw streaming iterator from IPFS node - no processing
2302
+ async def streaming_wrapper():
2303
+ async for chunk in self._get_ipfs_stream(cid, download_node):
2304
+ yield chunk
2305
+
2306
+ return streaming_wrapper()
2243
2307
 
2244
2308
  start_time = time.time()
2245
2309
 
@@ -2256,7 +2320,9 @@ class IPFSClient:
2256
2320
  try:
2257
2321
  # Create parent directories if they don't exist (only for file output mode)
2258
2322
  if not return_bytes:
2259
- os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
2323
+ os.makedirs(
2324
+ os.path.dirname(os.path.abspath(output_path)), exist_ok=True
2325
+ )
2260
2326
 
2261
2327
  download_client = AsyncIPFSClient(api_url=download_node)
2262
2328