hippius 0.2.21__tar.gz → 0.2.23__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.
- {hippius-0.2.21 → hippius-0.2.23}/PKG-INFO +1 -1
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/__init__.py +1 -1
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/client.py +8 -4
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/ipfs.py +55 -19
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/substrate.py +0 -23
- {hippius-0.2.21 → hippius-0.2.23}/pyproject.toml +1 -1
- {hippius-0.2.21 → hippius-0.2.23}/README.md +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/cli.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/cli_assets.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/cli_handlers.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/cli_parser.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/cli_rich.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/config.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/db/README.md +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/db/env.db.template +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/db/migrations/20241201000001_create_key_storage_tables.sql +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/db/setup_database.sh +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/db_utils.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/errors.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/ipfs_core.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/key_storage.py +0 -0
- {hippius-0.2.21 → hippius-0.2.23}/hippius_sdk/utils.py +0 -0
@@ -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.
|
29
|
+
__version__ = "0.2.23"
|
30
30
|
__all__ = [
|
31
31
|
"HippiusClient",
|
32
32
|
"IPFSClient",
|
@@ -517,7 +517,7 @@ class HippiusClient:
|
|
517
517
|
encrypt: bool,
|
518
518
|
seed_phrase: str,
|
519
519
|
store_node: str = "http://localhost:5001",
|
520
|
-
pin_node: str = "https://store.hippius.network"
|
520
|
+
pin_node: str = "https://store.hippius.network",
|
521
521
|
) -> S3PublishResult:
|
522
522
|
"""
|
523
523
|
Publish a file to IPFS and the Hippius marketplace in one operation.
|
@@ -542,7 +542,9 @@ class HippiusClient:
|
|
542
542
|
FileNotFoundError: If the file doesn't exist
|
543
543
|
ValueError: If encryption is requested but not available
|
544
544
|
"""
|
545
|
-
return await self.ipfs_client.s3_publish(
|
545
|
+
return await self.ipfs_client.s3_publish(
|
546
|
+
file_path, encrypt, seed_phrase, store_node, pin_node
|
547
|
+
)
|
546
548
|
|
547
549
|
async def s3_download(
|
548
550
|
self,
|
@@ -550,7 +552,7 @@ class HippiusClient:
|
|
550
552
|
output_path: str,
|
551
553
|
seed_phrase: str,
|
552
554
|
auto_decrypt: bool = True,
|
553
|
-
download_node: str = "http://localhost:5001"
|
555
|
+
download_node: str = "http://localhost:5001",
|
554
556
|
) -> S3DownloadResult:
|
555
557
|
"""
|
556
558
|
Download a file from IPFS with automatic decryption.
|
@@ -577,4 +579,6 @@ class HippiusClient:
|
|
577
579
|
FileNotFoundError: If the output directory doesn't exist
|
578
580
|
ValueError: If decryption fails
|
579
581
|
"""
|
580
|
-
return await self.ipfs_client.s3_download(
|
582
|
+
return await self.ipfs_client.s3_download(
|
583
|
+
cid, output_path, seed_phrase, auto_decrypt, download_node
|
584
|
+
)
|
@@ -509,10 +509,18 @@ class IPFSClient:
|
|
509
509
|
try:
|
510
510
|
ls_result = await self.client.ls(cid)
|
511
511
|
if isinstance(ls_result, dict) and ls_result.get("Objects", []):
|
512
|
-
# Check if we have Links
|
512
|
+
# Check if we have Links with non-empty names, which indicates a directory
|
513
|
+
# Links with empty names are file chunks, not directory entries
|
513
514
|
for obj in ls_result["Objects"]:
|
514
|
-
|
515
|
-
|
515
|
+
links = obj.get("Links", [])
|
516
|
+
if links:
|
517
|
+
# Check if any link has a non-empty name (directory entry)
|
518
|
+
# Links with empty names are file chunks, not directory entries
|
519
|
+
has_named_links = any(
|
520
|
+
link.get("Name", "").strip() for link in links
|
521
|
+
)
|
522
|
+
if has_named_links:
|
523
|
+
is_directory = True
|
516
524
|
break
|
517
525
|
except Exception:
|
518
526
|
# If ls check fails, continue treating as a regular file
|
@@ -1932,7 +1940,7 @@ class IPFSClient:
|
|
1932
1940
|
encrypt: bool,
|
1933
1941
|
seed_phrase: str,
|
1934
1942
|
store_node: str = "http://localhost:5001",
|
1935
|
-
pin_node: str = "https://store.hippius.network"
|
1943
|
+
pin_node: str = "https://store.hippius.network",
|
1936
1944
|
) -> S3PublishResult:
|
1937
1945
|
"""
|
1938
1946
|
Publish a file to IPFS and the Hippius marketplace in one operation.
|
@@ -2043,7 +2051,9 @@ class IPFSClient:
|
|
2043
2051
|
cid = result["Hash"]
|
2044
2052
|
logger.info(f"File uploaded to store node {store_node} with CID: {cid}")
|
2045
2053
|
except Exception as e:
|
2046
|
-
raise HippiusIPFSError(
|
2054
|
+
raise HippiusIPFSError(
|
2055
|
+
f"Failed to upload file to store node {store_node}: {str(e)}"
|
2056
|
+
)
|
2047
2057
|
|
2048
2058
|
# Step 2: Pin to pin_node (remote) for persistence and backup
|
2049
2059
|
try:
|
@@ -2051,7 +2061,9 @@ class IPFSClient:
|
|
2051
2061
|
await pin_client.pin(cid)
|
2052
2062
|
logger.info(f"File pinned to backup node {pin_node}")
|
2053
2063
|
except Exception as e:
|
2054
|
-
raise HippiusIPFSError(
|
2064
|
+
raise HippiusIPFSError(
|
2065
|
+
f"Failed to pin file to store node {store_node}: {str(e)}"
|
2066
|
+
)
|
2055
2067
|
|
2056
2068
|
# Publish to substrate marketplace
|
2057
2069
|
try:
|
@@ -2106,7 +2118,7 @@ class IPFSClient:
|
|
2106
2118
|
output_path: str,
|
2107
2119
|
seed_phrase: str,
|
2108
2120
|
auto_decrypt: bool = True,
|
2109
|
-
download_node: str = "http://localhost:5001"
|
2121
|
+
download_node: str = "http://localhost:5001",
|
2110
2122
|
) -> S3DownloadResult:
|
2111
2123
|
"""
|
2112
2124
|
Download a file from IPFS with automatic decryption.
|
@@ -2153,7 +2165,9 @@ class IPFSClient:
|
|
2153
2165
|
logger.info(f"File downloaded from {download_node} with CID: {cid}")
|
2154
2166
|
|
2155
2167
|
except Exception as e:
|
2156
|
-
raise HippiusIPFSError(
|
2168
|
+
raise HippiusIPFSError(
|
2169
|
+
f"Failed to download file from {download_node}: {str(e)}"
|
2170
|
+
)
|
2157
2171
|
|
2158
2172
|
# Get file info after download
|
2159
2173
|
size_bytes = os.path.getsize(output_path)
|
@@ -2184,8 +2198,12 @@ class IPFSClient:
|
|
2184
2198
|
f"File may not exist on download node {download_node}. "
|
2185
2199
|
f"Download URL: {download_url}"
|
2186
2200
|
)
|
2187
|
-
elif
|
2188
|
-
|
2201
|
+
elif (
|
2202
|
+
len(file_data) < 40
|
2203
|
+
): # PyNaCl encrypted data is at least 40 bytes (24-byte nonce + 16-byte auth tag + data)
|
2204
|
+
logger.info(
|
2205
|
+
f"File too small to be encrypted ({len(file_data)} bytes), treating as plaintext"
|
2206
|
+
)
|
2189
2207
|
decrypted = False
|
2190
2208
|
encryption_key_used = None
|
2191
2209
|
else:
|
@@ -2199,7 +2217,9 @@ class IPFSClient:
|
|
2199
2217
|
existing_key_b64 = await get_key_for_seed(seed_phrase)
|
2200
2218
|
|
2201
2219
|
if existing_key_b64:
|
2202
|
-
logger.debug(
|
2220
|
+
logger.debug(
|
2221
|
+
"Found encryption key for seed phrase, attempting decryption"
|
2222
|
+
)
|
2203
2223
|
decryption_attempted = True
|
2204
2224
|
encryption_key_used = existing_key_b64
|
2205
2225
|
|
@@ -2207,7 +2227,9 @@ class IPFSClient:
|
|
2207
2227
|
try:
|
2208
2228
|
import nacl.secret
|
2209
2229
|
|
2210
|
-
encryption_key_bytes = base64.b64decode(
|
2230
|
+
encryption_key_bytes = base64.b64decode(
|
2231
|
+
existing_key_b64
|
2232
|
+
)
|
2211
2233
|
box = nacl.secret.SecretBox(encryption_key_bytes)
|
2212
2234
|
decrypted_data = box.decrypt(file_data)
|
2213
2235
|
|
@@ -2217,11 +2239,17 @@ class IPFSClient:
|
|
2217
2239
|
|
2218
2240
|
decryption_successful = True
|
2219
2241
|
decrypted = True
|
2220
|
-
size_bytes = len(
|
2221
|
-
|
2242
|
+
size_bytes = len(
|
2243
|
+
decrypted_data
|
2244
|
+
) # Update size to decrypted size
|
2245
|
+
logger.info(
|
2246
|
+
"Successfully decrypted file using stored key"
|
2247
|
+
)
|
2222
2248
|
|
2223
2249
|
except Exception as decrypt_error:
|
2224
|
-
logger.debug(
|
2250
|
+
logger.debug(
|
2251
|
+
f"Decryption failed with stored key: {decrypt_error}"
|
2252
|
+
)
|
2225
2253
|
# Continue to try fallback decryption
|
2226
2254
|
else:
|
2227
2255
|
logger.debug("No encryption key found for seed phrase")
|
@@ -2243,7 +2271,9 @@ class IPFSClient:
|
|
2243
2271
|
|
2244
2272
|
decryption_successful = True
|
2245
2273
|
decrypted = True
|
2246
|
-
size_bytes = len(
|
2274
|
+
size_bytes = len(
|
2275
|
+
decrypted_data
|
2276
|
+
) # Update size to decrypted size
|
2247
2277
|
|
2248
2278
|
# Store the encryption key for the result
|
2249
2279
|
encryption_key_used = (
|
@@ -2251,14 +2281,20 @@ class IPFSClient:
|
|
2251
2281
|
if self.encryption_key
|
2252
2282
|
else None
|
2253
2283
|
)
|
2254
|
-
logger.info(
|
2284
|
+
logger.info(
|
2285
|
+
"Successfully decrypted file using client encryption key"
|
2286
|
+
)
|
2255
2287
|
|
2256
2288
|
except Exception as decrypt_error:
|
2257
|
-
logger.debug(
|
2289
|
+
logger.debug(
|
2290
|
+
f"Decryption failed with client key: {decrypt_error}"
|
2291
|
+
)
|
2258
2292
|
|
2259
2293
|
# Log final decryption status
|
2260
2294
|
if decryption_attempted and not decryption_successful:
|
2261
|
-
logger.info(
|
2295
|
+
logger.info(
|
2296
|
+
"File may not be encrypted or decryption keys don't match"
|
2297
|
+
)
|
2262
2298
|
elif not decryption_attempted:
|
2263
2299
|
logger.debug("No decryption attempted - no keys available")
|
2264
2300
|
|
@@ -1223,29 +1223,6 @@ class SubstrateClient:
|
|
1223
1223
|
Returns:
|
1224
1224
|
str: Transaction hash or status message
|
1225
1225
|
"""
|
1226
|
-
# First check if this CID exists in the user's storage requests
|
1227
|
-
try:
|
1228
|
-
cid_exists = await self.check_storage_request_exists(cid)
|
1229
|
-
if not cid_exists:
|
1230
|
-
raise HippiusAlreadyDeletedError(
|
1231
|
-
f"CID {cid} is not found in storage requests - may already be deleted"
|
1232
|
-
)
|
1233
|
-
except Exception as e:
|
1234
|
-
if not isinstance(e, HippiusAlreadyDeletedError):
|
1235
|
-
# If there was an error checking, but not our custom exception, wrap it
|
1236
|
-
raise HippiusSubstrateConnectionError(
|
1237
|
-
f"Error checking if CID exists: {str(e)}"
|
1238
|
-
)
|
1239
|
-
else:
|
1240
|
-
# Re-raise our custom exception
|
1241
|
-
raise
|
1242
|
-
|
1243
|
-
# Continue with cancellation if it exists
|
1244
|
-
if not self._ensure_keypair(seed_phrase):
|
1245
|
-
raise HippiusSubstrateAuthError(
|
1246
|
-
"Valid seed phrase must be provided or available in config"
|
1247
|
-
)
|
1248
|
-
|
1249
1226
|
# Initialize Substrate connection with seed phrase if needed
|
1250
1227
|
if not self._substrate:
|
1251
1228
|
self.connect(seed_phrase)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|