hippius 0.2.2__py3-none-any.whl → 0.2.4__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.
- {hippius-0.2.2.dist-info → hippius-0.2.4.dist-info}/METADATA +213 -156
- hippius-0.2.4.dist-info/RECORD +16 -0
- hippius_sdk/__init__.py +10 -21
- hippius_sdk/cli.py +282 -2627
- hippius_sdk/cli_assets.py +10 -0
- hippius_sdk/cli_handlers.py +2773 -0
- hippius_sdk/cli_parser.py +607 -0
- hippius_sdk/cli_rich.py +247 -0
- hippius_sdk/client.py +70 -22
- hippius_sdk/config.py +109 -142
- hippius_sdk/ipfs.py +435 -58
- hippius_sdk/ipfs_core.py +22 -1
- hippius_sdk/substrate.py +234 -553
- hippius_sdk/utils.py +84 -2
- hippius-0.2.2.dist-info/RECORD +0 -12
- {hippius-0.2.2.dist-info → hippius-0.2.4.dist-info}/WHEEL +0 -0
- {hippius-0.2.2.dist-info → hippius-0.2.4.dist-info}/entry_points.txt +0 -0
hippius_sdk/config.py
CHANGED
@@ -23,7 +23,7 @@ CONFIG_DIR = os.path.expanduser("~/.hippius")
|
|
23
23
|
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json")
|
24
24
|
DEFAULT_CONFIG = {
|
25
25
|
"ipfs": {
|
26
|
-
"gateway": "https://
|
26
|
+
"gateway": "https://get.hippius.network",
|
27
27
|
"api_url": "https://store.hippius.network",
|
28
28
|
"local_ipfs": False,
|
29
29
|
},
|
@@ -278,34 +278,30 @@ def decrypt_with_password(encrypted_data: str, salt: str, password: str) -> str:
|
|
278
278
|
Returns:
|
279
279
|
str: Decrypted data
|
280
280
|
"""
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
salt_bytes = base64.b64decode(salt)
|
281
|
+
# Decode the encrypted data and salt
|
282
|
+
encrypted_bytes = base64.b64decode(encrypted_data)
|
283
|
+
salt_bytes = base64.b64decode(salt)
|
285
284
|
|
286
|
-
|
287
|
-
|
285
|
+
# Derive the key from the password and salt
|
286
|
+
key, _ = _derive_key_from_password(password, salt_bytes)
|
288
287
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
# Create a SecretBox with our derived key
|
299
|
-
box = nacl.secret.SecretBox(key)
|
288
|
+
# Verify NaCl is available (imported at the top)
|
289
|
+
try:
|
290
|
+
if not hasattr(nacl, "secret") or not hasattr(nacl, "utils"):
|
291
|
+
raise ImportError("NaCl modules not available")
|
292
|
+
except ImportError:
|
293
|
+
raise ValueError(
|
294
|
+
"PyNaCl is required for decryption. Install it with: pip install pynacl"
|
295
|
+
)
|
300
296
|
|
301
|
-
|
302
|
-
|
297
|
+
# Create a SecretBox with our derived key
|
298
|
+
box = nacl.secret.SecretBox(key)
|
303
299
|
|
304
|
-
|
305
|
-
|
300
|
+
# Decrypt the data
|
301
|
+
decrypted_data = box.decrypt(encrypted_bytes)
|
306
302
|
|
307
|
-
|
308
|
-
|
303
|
+
# Return the decrypted string
|
304
|
+
return decrypted_data.decode("utf-8")
|
309
305
|
|
310
306
|
|
311
307
|
def encrypt_seed_phrase(
|
@@ -317,7 +313,7 @@ def encrypt_seed_phrase(
|
|
317
313
|
Args:
|
318
314
|
seed_phrase: The plain text seed phrase to encrypt
|
319
315
|
password: Optional password (if None, will prompt)
|
320
|
-
account_name: Optional name for the account (if None, uses
|
316
|
+
account_name: Optional name for the account (if None, uses active account)
|
321
317
|
|
322
318
|
Returns:
|
323
319
|
bool: True if encryption and saving was successful, False otherwise
|
@@ -344,30 +340,31 @@ def encrypt_seed_phrase(
|
|
344
340
|
|
345
341
|
config = load_config()
|
346
342
|
|
347
|
-
#
|
348
|
-
if
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
}
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
343
|
+
# Only use multi-account mode
|
344
|
+
# Use active account if no account specified
|
345
|
+
name_to_use = account_name
|
346
|
+
if name_to_use is None:
|
347
|
+
name_to_use = config["substrate"].get("active_account")
|
348
|
+
if not name_to_use:
|
349
|
+
# If no active account, we need a name
|
350
|
+
print("Error: No account name specified and no active account")
|
351
|
+
return False
|
352
|
+
|
353
|
+
# Ensure accounts structure exists
|
354
|
+
if "accounts" not in config["substrate"]:
|
355
|
+
config["substrate"]["accounts"] = {}
|
356
|
+
|
357
|
+
# Store the account data
|
358
|
+
config["substrate"]["accounts"][name_to_use] = {
|
359
|
+
"seed_phrase": encrypted_data,
|
360
|
+
"seed_phrase_encoded": True,
|
361
|
+
"seed_phrase_salt": salt,
|
362
|
+
"ss58_address": ss58_address,
|
363
|
+
}
|
364
|
+
|
365
|
+
# Set as active account if no active account exists
|
366
|
+
if not config["substrate"].get("active_account"):
|
367
|
+
config["substrate"]["active_account"] = name_to_use
|
371
368
|
|
372
369
|
return save_config(config)
|
373
370
|
|
@@ -384,60 +381,43 @@ def decrypt_seed_phrase(
|
|
384
381
|
|
385
382
|
Args:
|
386
383
|
password: Optional password (if None, will prompt)
|
387
|
-
account_name: Optional account name (if None, uses active account
|
384
|
+
account_name: Optional account name (if None, uses active account)
|
388
385
|
|
389
386
|
Returns:
|
390
387
|
Optional[str]: The decrypted seed phrase, or None if decryption failed
|
391
388
|
"""
|
392
|
-
|
393
|
-
config = load_config()
|
394
|
-
|
395
|
-
# Determine if we're using multi-account mode
|
396
|
-
if account_name is not None or config["substrate"].get("active_account"):
|
397
|
-
# Multi-account mode
|
398
|
-
name_to_use = account_name or config["substrate"].get("active_account")
|
399
|
-
|
400
|
-
if not name_to_use:
|
401
|
-
print("Error: No account specified and no active account")
|
402
|
-
return None
|
403
|
-
|
404
|
-
if name_to_use not in config["substrate"].get("accounts", {}):
|
405
|
-
print(f"Error: Account '{name_to_use}' not found")
|
406
|
-
return None
|
407
|
-
|
408
|
-
account_data = config["substrate"]["accounts"][name_to_use]
|
409
|
-
is_encoded = account_data.get("seed_phrase_encoded", False)
|
389
|
+
config = load_config()
|
410
390
|
|
411
|
-
|
412
|
-
|
391
|
+
# Only use the multi-account system
|
392
|
+
name_to_use = account_name or config["substrate"].get("active_account")
|
413
393
|
|
414
|
-
|
415
|
-
|
394
|
+
if not name_to_use:
|
395
|
+
print("Error: No account specified and no active account")
|
396
|
+
return None
|
416
397
|
|
417
|
-
|
418
|
-
|
419
|
-
|
398
|
+
if name_to_use not in config["substrate"].get("accounts", {}):
|
399
|
+
print(f"Error: Account '{name_to_use}' not found")
|
400
|
+
return None
|
420
401
|
|
421
|
-
|
422
|
-
|
402
|
+
account_data = config["substrate"]["accounts"][name_to_use]
|
403
|
+
is_encoded = account_data.get("seed_phrase_encoded", False)
|
423
404
|
|
424
|
-
|
425
|
-
|
405
|
+
if not is_encoded:
|
406
|
+
return account_data.get("seed_phrase")
|
426
407
|
|
427
|
-
|
428
|
-
|
429
|
-
return None
|
408
|
+
encrypted_data = account_data.get("seed_phrase")
|
409
|
+
salt = account_data.get("seed_phrase_salt")
|
430
410
|
|
431
|
-
|
432
|
-
|
433
|
-
|
411
|
+
if not encrypted_data or not salt:
|
412
|
+
print("Error: No encrypted seed phrase found or missing salt")
|
413
|
+
return None
|
434
414
|
|
435
|
-
|
436
|
-
|
415
|
+
# Get password from user if not provided
|
416
|
+
if password is None:
|
417
|
+
password = getpass.getpass("Enter password to decrypt seed phrase: \n\n")
|
437
418
|
|
438
|
-
|
439
|
-
|
440
|
-
return None
|
419
|
+
# Decrypt the seed phrase
|
420
|
+
return decrypt_with_password(encrypted_data, salt, password)
|
441
421
|
|
442
422
|
|
443
423
|
def get_seed_phrase(
|
@@ -448,45 +428,31 @@ def get_seed_phrase(
|
|
448
428
|
|
449
429
|
Args:
|
450
430
|
password: Optional password for decryption (if None and needed, will prompt)
|
451
|
-
account_name: Optional account name (if None, uses active account
|
431
|
+
account_name: Optional account name (if None, uses active account)
|
452
432
|
|
453
433
|
Returns:
|
454
434
|
Optional[str]: The seed phrase, or None if not available
|
455
435
|
"""
|
456
436
|
config = load_config()
|
457
437
|
|
458
|
-
#
|
459
|
-
|
460
|
-
# Multi-account mode
|
461
|
-
name_to_use = account_name or config["substrate"].get("active_account")
|
438
|
+
# Only use the multi-account system
|
439
|
+
name_to_use = account_name or config["substrate"].get("active_account")
|
462
440
|
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
if name_to_use not in config["substrate"].get("accounts", {}):
|
468
|
-
print(f"Error: Account '{name_to_use}' not found")
|
469
|
-
return None
|
441
|
+
if not name_to_use:
|
442
|
+
print("Error: No account specified and no active account")
|
443
|
+
return None
|
470
444
|
|
471
|
-
|
472
|
-
|
445
|
+
if name_to_use not in config["substrate"].get("accounts", {}):
|
446
|
+
print(f"Error: Account '{name_to_use}' not found")
|
447
|
+
return None
|
473
448
|
|
474
|
-
|
475
|
-
|
476
|
-
is_encoded = config["substrate"].get("seed_phrase_encoded", False)
|
449
|
+
account_data = config["substrate"]["accounts"][name_to_use]
|
450
|
+
is_encoded = account_data.get("seed_phrase_encoded", False)
|
477
451
|
|
478
452
|
if is_encoded:
|
479
|
-
|
480
|
-
return decrypt_seed_phrase(password, account_name)
|
453
|
+
return decrypt_seed_phrase(password, name_to_use)
|
481
454
|
else:
|
482
|
-
|
483
|
-
if account_name is not None or config["substrate"].get("active_account"):
|
484
|
-
# Multi-account mode
|
485
|
-
name_to_use = account_name or config["substrate"].get("active_account")
|
486
|
-
return config["substrate"]["accounts"][name_to_use].get("seed_phrase")
|
487
|
-
else:
|
488
|
-
# Legacy mode
|
489
|
-
return config["substrate"].get("seed_phrase")
|
455
|
+
return account_data.get("seed_phrase")
|
490
456
|
|
491
457
|
|
492
458
|
def set_seed_phrase(
|
@@ -502,7 +468,7 @@ def set_seed_phrase(
|
|
502
468
|
seed_phrase: The seed phrase to store
|
503
469
|
encode: Whether to encrypt the seed phrase (requires password)
|
504
470
|
password: Optional password for encryption (if None and encode=True, will prompt)
|
505
|
-
account_name: Optional name for the account (if None, uses
|
471
|
+
account_name: Optional name for the account (if None, uses active account)
|
506
472
|
|
507
473
|
Returns:
|
508
474
|
bool: True if saving was successful, False otherwise
|
@@ -520,30 +486,31 @@ def set_seed_phrase(
|
|
520
486
|
except Exception as e:
|
521
487
|
print(f"Warning: Could not derive SS58 address: {e}")
|
522
488
|
|
523
|
-
#
|
524
|
-
if
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
}
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
489
|
+
# Only use multi-account mode
|
490
|
+
# Use active account if no account specified
|
491
|
+
name_to_use = account_name
|
492
|
+
if name_to_use is None:
|
493
|
+
name_to_use = config["substrate"].get("active_account")
|
494
|
+
if not name_to_use:
|
495
|
+
# If no active account, we need a name
|
496
|
+
print("Error: No account name specified and no active account")
|
497
|
+
return False
|
498
|
+
|
499
|
+
# Ensure accounts structure exists
|
500
|
+
if "accounts" not in config["substrate"]:
|
501
|
+
config["substrate"]["accounts"] = {}
|
502
|
+
|
503
|
+
# Store the account data
|
504
|
+
config["substrate"]["accounts"][name_to_use] = {
|
505
|
+
"seed_phrase": seed_phrase,
|
506
|
+
"seed_phrase_encoded": False,
|
507
|
+
"seed_phrase_salt": None,
|
508
|
+
"ss58_address": ss58_address,
|
509
|
+
}
|
510
|
+
|
511
|
+
# Set as active account if no active account exists
|
512
|
+
if not config["substrate"].get("active_account"):
|
513
|
+
config["substrate"]["active_account"] = name_to_use
|
547
514
|
|
548
515
|
return save_config(config)
|
549
516
|
|