bittensor-wallet 2.0.2__tar.gz → 2.0.3__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.
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.circleci/config.yml +2 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/CHANGELOG.MD +3 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/Cargo.lock +11 -1
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/Cargo.toml +2 -1
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/PKG-INFO +2 -2
- bittensor_wallet-2.0.3/bittensor_wallet/__init__.py +16 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/errors/__init__.py +1 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/pyproject.toml +2 -2
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/constants.rs +1 -1
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/errors.rs +33 -1
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/keyfile.rs +23 -27
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/lib.rs +1 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/wallet.rs +23 -29
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/tests/test_keyfile.py +0 -1
- bittensor_wallet-2.0.2/bittensor_wallet/__init__.py +0 -16
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.flake8 +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.github/workflows/release.yml +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/.gitignore +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/LICENSE +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/README.md +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/RUST-README.md +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/keyfile/__init__.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/keypair/__init__.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/mock/__init__.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/mock/keyfile_mock.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/mock/wallet_mock.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/utils/__init__.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/bittensor_wallet/wallet/__init__.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/requirements/dev.txt +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/requirements/prod.txt +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/config.rs +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/keypair.rs +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/src/utils.rs +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/tests/test_utils.py +0 -0
- {bittensor_wallet-2.0.2 → bittensor_wallet-2.0.3}/tests/test_wallet.py +0 -0
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
## What's Changed
|
|
6
6
|
|
|
7
7
|
* Add the ability to use environment variables to store hot/coldkey passwords by @roman-opentensor in https://github.com/opentensor/btwallet/pull/46
|
|
8
|
+
* Fix wallet paths outside userhome by @camfairchild in https://github.com/opentensor/btwallet/pull/59
|
|
9
|
+
* fix https://github.com/opentensor/btwallet/issues/51 by @camfairchild in https://github.com/opentensor/btwallet/pull/56
|
|
10
|
+
* password fixes by @roman-opentensor
|
|
8
11
|
* fix/roman/fix-config-parsing by @roman-opentensor in https://github.com/opentensor/btwallet/pull/47
|
|
9
12
|
|
|
10
13
|
**Full Changelog**: https://github.com/opentensor/btwallet/compare/v2.0.1...v2.0.2
|
|
@@ -352,7 +352,7 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
|
|
352
352
|
|
|
353
353
|
[[package]]
|
|
354
354
|
name = "bittensor_wallet"
|
|
355
|
-
version = "2.0.
|
|
355
|
+
version = "2.0.3"
|
|
356
356
|
dependencies = [
|
|
357
357
|
"ansible-vault",
|
|
358
358
|
"base64 0.22.1",
|
|
@@ -371,6 +371,7 @@ dependencies = [
|
|
|
371
371
|
"serde",
|
|
372
372
|
"serde_json",
|
|
373
373
|
"sha2 0.10.8",
|
|
374
|
+
"shellexpand",
|
|
374
375
|
"sodiumoxide",
|
|
375
376
|
"sp-core",
|
|
376
377
|
]
|
|
@@ -2230,6 +2231,15 @@ dependencies = [
|
|
|
2230
2231
|
"lazy_static",
|
|
2231
2232
|
]
|
|
2232
2233
|
|
|
2234
|
+
[[package]]
|
|
2235
|
+
name = "shellexpand"
|
|
2236
|
+
version = "3.1.0"
|
|
2237
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2238
|
+
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
|
|
2239
|
+
dependencies = [
|
|
2240
|
+
"dirs",
|
|
2241
|
+
]
|
|
2242
|
+
|
|
2233
2243
|
[[package]]
|
|
2234
2244
|
name = "shlex"
|
|
2235
2245
|
version = "1.3.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "bittensor_wallet"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
[lib]
|
|
@@ -27,6 +27,7 @@ base64 = "0.22.1"
|
|
|
27
27
|
scrypt = "0.11.0"
|
|
28
28
|
pkcs8 = "0.10.2"
|
|
29
29
|
schnorrkel = "0.11.4"
|
|
30
|
+
shellexpand = "3.1.0"
|
|
30
31
|
|
|
31
32
|
[features]
|
|
32
33
|
extension-module = ["pyo3/extension-module"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: bittensor-wallet
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Topic :: Software Development :: Build Tools
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Dist: termcolor
|
|
20
20
|
Requires-Dist: eth-utils <2.3.0
|
|
21
21
|
Requires-Dist: password-strength
|
|
22
|
-
Requires-Dist: cryptography ~=
|
|
22
|
+
Requires-Dist: cryptography ~=43.0.1
|
|
23
23
|
Requires-Dist: ansible ~=6.7
|
|
24
24
|
Requires-Dist: ansible-vault ~=2.1
|
|
25
25
|
Requires-Dist: munch ~=2.5.0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from bittensor_wallet.bittensor_wallet import (
|
|
2
|
+
# classes
|
|
3
|
+
Config as Config,
|
|
4
|
+
Keyfile as Keyfile,
|
|
5
|
+
Keypair as Keypair,
|
|
6
|
+
Wallet as Wallet,
|
|
7
|
+
# modules
|
|
8
|
+
config as config,
|
|
9
|
+
errors as errors,
|
|
10
|
+
keyfile as keyfile,
|
|
11
|
+
keypair as keypair,
|
|
12
|
+
utils as utils,
|
|
13
|
+
wallet as wallet,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__version__ = "2.0.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bittensor-wallet"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.3"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {file = "LICENSE"}
|
|
@@ -10,7 +10,7 @@ dependencies = [
|
|
|
10
10
|
"termcolor",
|
|
11
11
|
"eth-utils<2.3.0",
|
|
12
12
|
"password_strength",
|
|
13
|
-
"cryptography~=
|
|
13
|
+
"cryptography~=43.0.1",
|
|
14
14
|
"ansible~=6.7",
|
|
15
15
|
"ansible_vault~=2.1",
|
|
16
16
|
"munch~=2.5.0",
|
|
@@ -2,13 +2,14 @@ use pyo3::exceptions::PyException;
|
|
|
2
2
|
use pyo3::prelude::*;
|
|
3
3
|
use std::{error, fmt};
|
|
4
4
|
|
|
5
|
+
// KeyFileError
|
|
5
6
|
#[pyclass(extends=PyException)]
|
|
6
7
|
#[derive(Debug)]
|
|
7
8
|
pub struct KeyFileError {
|
|
8
9
|
pub message: String,
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
/// Error thrown when the keyfile is corrupt, non-writable, non-readable
|
|
12
|
+
/// Error thrown when the keyfile is corrupt, non-writable, non-readable.
|
|
12
13
|
#[pymethods]
|
|
13
14
|
impl KeyFileError {
|
|
14
15
|
#[new]
|
|
@@ -31,6 +32,7 @@ impl fmt::Display for KeyFileError {
|
|
|
31
32
|
|
|
32
33
|
impl error::Error for KeyFileError {}
|
|
33
34
|
|
|
35
|
+
// ConfigurationError
|
|
34
36
|
#[pyclass(extends=PyException)]
|
|
35
37
|
#[derive(Debug)]
|
|
36
38
|
pub struct ConfigurationError {
|
|
@@ -59,3 +61,33 @@ impl fmt::Display for ConfigurationError {
|
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
impl error::Error for ConfigurationError {}
|
|
64
|
+
|
|
65
|
+
// PasswordError
|
|
66
|
+
#[pyclass(extends=PyException)]
|
|
67
|
+
#[derive(Debug)]
|
|
68
|
+
pub struct PasswordError {
|
|
69
|
+
pub message: String,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// PasswordError occurs if the password used for decryption is invalid.
|
|
73
|
+
#[pymethods]
|
|
74
|
+
impl PasswordError {
|
|
75
|
+
#[new]
|
|
76
|
+
#[pyo3(signature = (message=None))]
|
|
77
|
+
pub fn new(message: Option<String>) -> Self {
|
|
78
|
+
let msg = message.unwrap_or_default();
|
|
79
|
+
PasswordError { message: msg }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
pub fn __str__(&self) -> String {
|
|
83
|
+
self.message.clone()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
impl fmt::Display for PasswordError {
|
|
88
|
+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
89
|
+
write!(f, "PasswordError: {}", self.message)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
impl error::Error for PasswordError {}
|
|
@@ -9,7 +9,7 @@ use std::env;
|
|
|
9
9
|
use std::fs;
|
|
10
10
|
use std::io::{Read, Write};
|
|
11
11
|
use std::os::unix::fs::PermissionsExt;
|
|
12
|
-
use std::path::
|
|
12
|
+
use std::path::PathBuf;
|
|
13
13
|
use std::str::from_utf8;
|
|
14
14
|
|
|
15
15
|
use ansible_vault::{decrypt_vault, encrypt_vault};
|
|
@@ -19,7 +19,7 @@ use passwords::analyzer;
|
|
|
19
19
|
use passwords::scorer;
|
|
20
20
|
use serde_json::json;
|
|
21
21
|
|
|
22
|
-
use crate::errors::KeyFileError;
|
|
22
|
+
use crate::errors::{KeyFileError, PasswordError};
|
|
23
23
|
use crate::keypair::Keypair;
|
|
24
24
|
use crate::utils;
|
|
25
25
|
|
|
@@ -414,7 +414,7 @@ pub fn decrypt_keyfile_data(
|
|
|
414
414
|
.ok_or(PyErr::new::<PyRuntimeError, _>("Invalid nonce."))?;
|
|
415
415
|
let ciphertext = &data[secretbox::NONCEBYTES..];
|
|
416
416
|
secretbox::open(ciphertext, &nonce, key)
|
|
417
|
-
.map_err(|_| PyErr::new::<
|
|
417
|
+
.map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for nacl decryption."))
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
// decrypt of keyfile_data with legacy way
|
|
@@ -428,7 +428,7 @@ pub fn decrypt_keyfile_data(
|
|
|
428
428
|
let keyfile_data_str = from_utf8(keyfile_data)?;
|
|
429
429
|
fernet
|
|
430
430
|
.decrypt(keyfile_data_str)
|
|
431
|
-
.map_err(|_| PyErr::new::<
|
|
431
|
+
.map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for legacy decryption."))
|
|
432
432
|
}
|
|
433
433
|
|
|
434
434
|
let mut password = password;
|
|
@@ -453,21 +453,21 @@ pub fn decrypt_keyfile_data(
|
|
|
453
453
|
if keyfile_data_is_encrypted_nacl(py, keyfile_data)? {
|
|
454
454
|
let key = derive_key(password.as_bytes());
|
|
455
455
|
let decrypted_data = nacl_decrypt(keyfile_data, &key)
|
|
456
|
-
.map_err(|_| PyErr::new::<
|
|
456
|
+
.map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for decryption."))?;
|
|
457
457
|
return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
// Ansible Vault decryption
|
|
461
461
|
if keyfile_data_is_encrypted_ansible(py, keyfile_data)? {
|
|
462
462
|
let decrypted_data = decrypt_vault(keyfile_data, password.as_str())
|
|
463
|
-
.map_err(|_| PyErr::new::<
|
|
463
|
+
.map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for decryption."))?;
|
|
464
464
|
return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
// Legacy decryption
|
|
468
468
|
if keyfile_data_is_encrypted_legacy(py, keyfile_data)? {
|
|
469
469
|
let decrypted_data = legacy_decrypt(&password, keyfile_data)
|
|
470
|
-
.map_err(|_| PyErr::new::<
|
|
470
|
+
.map_err(|_| PyErr::new::<PasswordError, _>("Wrong password for decryption."))?;
|
|
471
471
|
return Ok(PyBytes::new_bound(py, &decrypted_data).into_py(py));
|
|
472
472
|
}
|
|
473
473
|
|
|
@@ -498,10 +498,6 @@ fn encrypt_password(key: String, value: String) -> String {
|
|
|
498
498
|
let encrypted_char = (c as u8) ^ (key.chars().nth(i % key.len()).unwrap() as u8);
|
|
499
499
|
encrypted.push(encrypted_char as char);
|
|
500
500
|
}
|
|
501
|
-
println!(
|
|
502
|
-
">>> key: {}, value: {}, encrypted: {}",
|
|
503
|
-
key, value, encrypted
|
|
504
|
-
);
|
|
505
501
|
encrypted
|
|
506
502
|
}
|
|
507
503
|
|
|
@@ -519,6 +515,7 @@ fn decrypt_password(data: String, key: String) -> String {
|
|
|
519
515
|
#[pyclass(subclass)]
|
|
520
516
|
pub struct Keyfile {
|
|
521
517
|
path: String,
|
|
518
|
+
_path: PathBuf,
|
|
522
519
|
name: String,
|
|
523
520
|
should_save_to_env: bool,
|
|
524
521
|
}
|
|
@@ -528,10 +525,11 @@ impl Keyfile {
|
|
|
528
525
|
#[new]
|
|
529
526
|
#[pyo3(signature = (path, name=None, should_save_to_env=false))]
|
|
530
527
|
pub fn new(path: String, name: Option<String>, should_save_to_env: bool) -> PyResult<Self> {
|
|
531
|
-
let
|
|
528
|
+
let expanded_path: PathBuf = PathBuf::from(expand_tilde(&path));
|
|
532
529
|
let name = name.unwrap_or_else(|| "Keyfile".to_string());
|
|
533
530
|
Ok(Keyfile {
|
|
534
531
|
path,
|
|
532
|
+
_path: expanded_path,
|
|
535
533
|
name,
|
|
536
534
|
should_save_to_env,
|
|
537
535
|
})
|
|
@@ -653,9 +651,7 @@ impl Keyfile {
|
|
|
653
651
|
|
|
654
652
|
/// Creates directories for the path if they do not exist.
|
|
655
653
|
pub fn make_dirs(&self) -> PyResult<()> {
|
|
656
|
-
|
|
657
|
-
let path: &Path = self.path.as_ref();
|
|
658
|
-
if let Some(directory) = path.parent() {
|
|
654
|
+
if let Some(directory) = self._path.parent() {
|
|
659
655
|
// check if the dir is exit already
|
|
660
656
|
if !directory.exists() {
|
|
661
657
|
// create the dir if not
|
|
@@ -670,7 +666,7 @@ impl Keyfile {
|
|
|
670
666
|
/// Returns:
|
|
671
667
|
/// readable (bool): ``True`` if the file is readable.
|
|
672
668
|
pub fn exists_on_device(&self) -> PyResult<bool> {
|
|
673
|
-
Ok(
|
|
669
|
+
Ok(self._path.exists())
|
|
674
670
|
}
|
|
675
671
|
|
|
676
672
|
/// Returns ``True`` if the file under path is readable.
|
|
@@ -681,7 +677,7 @@ impl Keyfile {
|
|
|
681
677
|
}
|
|
682
678
|
|
|
683
679
|
// get file metadata
|
|
684
|
-
let metadata = fs::metadata(&self.
|
|
680
|
+
let metadata = fs::metadata(&self._path).map_err(|e| {
|
|
685
681
|
PyErr::new::<PyIOError, _>(format!("Failed to get metadata for file: {}.", e))
|
|
686
682
|
})?;
|
|
687
683
|
|
|
@@ -703,7 +699,7 @@ impl Keyfile {
|
|
|
703
699
|
}
|
|
704
700
|
|
|
705
701
|
// get file metadata
|
|
706
|
-
let metadata = fs::metadata(&self.
|
|
702
|
+
let metadata = fs::metadata(&self._path).map_err(|e| {
|
|
707
703
|
PyErr::new::<PyIOError, _>(format!("Failed to get metadata for file: {}", e))
|
|
708
704
|
})?;
|
|
709
705
|
|
|
@@ -993,7 +989,7 @@ impl Keyfile {
|
|
|
993
989
|
}
|
|
994
990
|
|
|
995
991
|
// open and read the file
|
|
996
|
-
let mut file = fs::File::open(&self.
|
|
992
|
+
let mut file = fs::File::open(&self._path)
|
|
997
993
|
.map_err(|e| PyErr::new::<PyOSError, _>(format!("Failed to open file: {}.", e)))?;
|
|
998
994
|
let mut data_vec = Vec::new();
|
|
999
995
|
file.read_to_end(&mut data_vec)
|
|
@@ -1029,7 +1025,7 @@ impl Keyfile {
|
|
|
1029
1025
|
.write(true)
|
|
1030
1026
|
.create(true)
|
|
1031
1027
|
.truncate(true) // cleanup if rewrite
|
|
1032
|
-
.open(&self.
|
|
1028
|
+
.open(&self._path)
|
|
1033
1029
|
.map_err(|e| PyErr::new::<PyIOError, _>(format!("Failed to open file: {}.", e)))?;
|
|
1034
1030
|
|
|
1035
1031
|
// write data
|
|
@@ -1038,9 +1034,9 @@ impl Keyfile {
|
|
|
1038
1034
|
.map_err(|e| PyErr::new::<PyIOError, _>(format!("Failed to write to file: {}.", e)))?;
|
|
1039
1035
|
|
|
1040
1036
|
// set permissions
|
|
1041
|
-
let mut permissions = fs::metadata(&self.
|
|
1037
|
+
let mut permissions = fs::metadata(&self._path)?.permissions();
|
|
1042
1038
|
permissions.set_mode(0o600); // just for owner
|
|
1043
|
-
fs::set_permissions(&self.
|
|
1039
|
+
fs::set_permissions(&self._path, permissions).map_err(|e| {
|
|
1044
1040
|
PyErr::new::<PyPermissionError, _>(format!("Failed to set permissions: {}.", e))
|
|
1045
1041
|
})?;
|
|
1046
1042
|
Ok(())
|
|
@@ -1048,7 +1044,7 @@ impl Keyfile {
|
|
|
1048
1044
|
|
|
1049
1045
|
/// Saves the key's password to the associated local environment variable.
|
|
1050
1046
|
#[pyo3(signature = (password=None))]
|
|
1051
|
-
fn save_password_to_env(&self, password: Option<String>, py: Python) -> PyResult<
|
|
1047
|
+
fn save_password_to_env(&self, password: Option<String>, py: Python) -> PyResult<String> {
|
|
1052
1048
|
// checking the password
|
|
1053
1049
|
let password = match password {
|
|
1054
1050
|
Some(pwd) => pwd,
|
|
@@ -1056,7 +1052,7 @@ impl Keyfile {
|
|
|
1056
1052
|
Ok(pwd) => pwd,
|
|
1057
1053
|
Err(e) => {
|
|
1058
1054
|
utils::print(format!("Error asking password: {:?}.\n", e));
|
|
1059
|
-
return Ok(
|
|
1055
|
+
return Ok("".parse()?);
|
|
1060
1056
|
}
|
|
1061
1057
|
},
|
|
1062
1058
|
};
|
|
@@ -1066,21 +1062,21 @@ impl Keyfile {
|
|
|
1066
1062
|
// encrypt password
|
|
1067
1063
|
let encrypted_password = encrypt_password(self.env_var_name()?, password);
|
|
1068
1064
|
// store encrypted password
|
|
1069
|
-
env::set_var(&env_var_name, encrypted_password);
|
|
1065
|
+
env::set_var(&env_var_name, &encrypted_password);
|
|
1070
1066
|
|
|
1071
1067
|
let message = format!(
|
|
1072
1068
|
"The password has been saved to environment variable '{}'.\n",
|
|
1073
1069
|
env_var_name
|
|
1074
1070
|
);
|
|
1075
1071
|
utils::print(message);
|
|
1076
|
-
Ok(
|
|
1072
|
+
Ok(encrypted_password)
|
|
1077
1073
|
}
|
|
1078
1074
|
Err(e) => {
|
|
1079
1075
|
utils::print(format!(
|
|
1080
1076
|
"Error saving environment variable name: {:?}.\n",
|
|
1081
1077
|
e
|
|
1082
1078
|
));
|
|
1083
|
-
Ok(
|
|
1079
|
+
Ok("".parse()?)
|
|
1084
1080
|
}
|
|
1085
1081
|
}
|
|
1086
1082
|
}
|
|
@@ -36,6 +36,7 @@ fn register_errors_module(main_module: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
36
36
|
let errors_module = PyModule::new_bound(main_module.py(), "errors")?;
|
|
37
37
|
errors_module.add_class::<errors::ConfigurationError>()?;
|
|
38
38
|
errors_module.add_class::<errors::KeyFileError>()?;
|
|
39
|
+
errors_module.add_class::<errors::PasswordError>()?;
|
|
39
40
|
main_module.add_submodule(&errors_module)
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -4,6 +4,7 @@ use pyo3::types::{IntoPyDict, PyString, PyType};
|
|
|
4
4
|
|
|
5
5
|
use colored::Colorize;
|
|
6
6
|
use std::env;
|
|
7
|
+
use std::path::PathBuf;
|
|
7
8
|
|
|
8
9
|
use crate::config::Config;
|
|
9
10
|
use crate::constants::{BT_WALLET_HOTKEY, BT_WALLET_NAME, BT_WALLET_PATH};
|
|
@@ -12,10 +13,6 @@ use crate::keyfile::Keyfile;
|
|
|
12
13
|
use crate::keypair::Keypair;
|
|
13
14
|
use crate::utils::{self, is_valid_bittensor_address_or_public_key};
|
|
14
15
|
|
|
15
|
-
use dirs::home_dir;
|
|
16
|
-
|
|
17
|
-
type PyRuntimeError = KeyFileError;
|
|
18
|
-
|
|
19
16
|
/// Display the mnemonic and a warning message to keep the mnemonic safe.
|
|
20
17
|
#[pyfunction]
|
|
21
18
|
#[pyo3(signature = (mnemonic, key_type))]
|
|
@@ -34,7 +31,11 @@ pub fn display_mnemonic_msg(mnemonic: String, key_type: &str) {
|
|
|
34
31
|
}
|
|
35
32
|
|
|
36
33
|
// Function to safely retrieve attribute as Option<String> from passed python object
|
|
37
|
-
fn get_attribute_string(
|
|
34
|
+
fn get_attribute_string(
|
|
35
|
+
py: Python,
|
|
36
|
+
obj: &Bound<PyAny>,
|
|
37
|
+
attr_name: &str,
|
|
38
|
+
) -> PyResult<Option<String>> {
|
|
38
39
|
match obj.getattr(attr_name) {
|
|
39
40
|
Ok(attr) => {
|
|
40
41
|
if attr.is_none() {
|
|
@@ -61,6 +62,8 @@ pub struct Wallet {
|
|
|
61
62
|
pub path: String,
|
|
62
63
|
pub hotkey: String,
|
|
63
64
|
|
|
65
|
+
_path: PathBuf,
|
|
66
|
+
|
|
64
67
|
_coldkey: Option<Keypair>,
|
|
65
68
|
_coldkeypub: Option<Keypair>,
|
|
66
69
|
_hotkey: Option<Keypair>,
|
|
@@ -82,9 +85,8 @@ impl Wallet {
|
|
|
82
85
|
hotkey: Option<String>,
|
|
83
86
|
path: Option<String>,
|
|
84
87
|
config: Option<PyObject>,
|
|
85
|
-
py: Python
|
|
88
|
+
py: Python,
|
|
86
89
|
) -> PyResult<Wallet> {
|
|
87
|
-
|
|
88
90
|
// default config's values if config and config.wallet exist
|
|
89
91
|
let mut conf_name: Option<String> = None;
|
|
90
92
|
let mut conf_hotkey: Option<String> = None;
|
|
@@ -128,15 +130,19 @@ impl Wallet {
|
|
|
128
130
|
let final_path = if let Some(path) = path {
|
|
129
131
|
path
|
|
130
132
|
} else if let Some(conf_path) = conf_path {
|
|
131
|
-
conf_path
|
|
133
|
+
conf_path
|
|
132
134
|
} else {
|
|
133
135
|
BT_WALLET_PATH.to_string()
|
|
134
136
|
};
|
|
135
137
|
|
|
138
|
+
let expanded_path: PathBuf = PathBuf::from(shellexpand::tilde(&final_path).to_string());
|
|
139
|
+
|
|
136
140
|
Ok(Wallet {
|
|
137
141
|
name: final_name,
|
|
138
142
|
hotkey: final_hotkey,
|
|
139
|
-
path: final_path,
|
|
143
|
+
path: final_path.clone(),
|
|
144
|
+
|
|
145
|
+
_path: expanded_path,
|
|
140
146
|
|
|
141
147
|
_coldkey: None,
|
|
142
148
|
_coldkeypub: None,
|
|
@@ -146,14 +152,14 @@ impl Wallet {
|
|
|
146
152
|
|
|
147
153
|
fn __str__(&self) -> PyResult<String> {
|
|
148
154
|
Ok(format!(
|
|
149
|
-
"Wallet (Name: '{:}', Hotkey: '{:}', Path: '
|
|
155
|
+
"Wallet (Name: '{:}', Hotkey: '{:}', Path: '{:}')",
|
|
150
156
|
self.name, self.hotkey, self.path
|
|
151
157
|
))
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
fn __repr__(&self) -> PyResult<String> {
|
|
155
161
|
Ok(format!(
|
|
156
|
-
"name: '{:}', hotkey: '{:}', path: '
|
|
162
|
+
"name: '{:}', hotkey: '{:}', path: '{:}'",
|
|
157
163
|
self.name, self.hotkey, self.path
|
|
158
164
|
))
|
|
159
165
|
}
|
|
@@ -183,8 +189,8 @@ impl Wallet {
|
|
|
183
189
|
env::var("BT_WALLET_NAME").unwrap_or_else(|_| BT_WALLET_NAME.to_string());
|
|
184
190
|
let default_hotkey =
|
|
185
191
|
env::var("BT_WALLET_HOTKEY").unwrap_or_else(|_| BT_WALLET_HOTKEY.to_string());
|
|
186
|
-
let default_path =
|
|
187
|
-
|
|
192
|
+
let default_path = env::var("BT_WALLET_PATH")
|
|
193
|
+
.unwrap_or_else(|_| format!("~/{}", BT_WALLET_PATH.to_string()));
|
|
188
194
|
|
|
189
195
|
let prefix_str = if let Some(value) = prefix {
|
|
190
196
|
format!("\"{}\"", value)
|
|
@@ -383,12 +389,8 @@ except argparse.ArgumentError:
|
|
|
383
389
|
/// Created Hot Keyfile for Keypair
|
|
384
390
|
#[pyo3(signature = (save_hotkey_to_env=false))]
|
|
385
391
|
pub fn create_hotkey_file(&self, save_hotkey_to_env: bool) -> PyResult<Keyfile> {
|
|
386
|
-
// get home dir
|
|
387
|
-
let home = home_dir()
|
|
388
|
-
.ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
|
|
389
|
-
|
|
390
392
|
// concatenate wallet path
|
|
391
|
-
let wallet_path =
|
|
393
|
+
let wallet_path = self._path.join(&self.name);
|
|
392
394
|
|
|
393
395
|
// concatenate hotkey path
|
|
394
396
|
let hotkey_path = wallet_path.join("hotkeys").join(&self.hotkey);
|
|
@@ -409,12 +411,8 @@ except argparse.ArgumentError:
|
|
|
409
411
|
/// Created Cold Keyfile for Keypair
|
|
410
412
|
#[pyo3(signature = (save_coldkey_to_env=false))]
|
|
411
413
|
pub fn create_coldkey_file(&self, save_coldkey_to_env: bool) -> PyResult<Keyfile> {
|
|
412
|
-
// get home dir
|
|
413
|
-
let home = home_dir()
|
|
414
|
-
.ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
|
|
415
|
-
|
|
416
414
|
// concatenate wallet path
|
|
417
|
-
let wallet_path =
|
|
415
|
+
let wallet_path = PathBuf::from(&self._path).join(&self.name);
|
|
418
416
|
|
|
419
417
|
// concatenate coldkey path
|
|
420
418
|
let coldkey_path = wallet_path.join("coldkey");
|
|
@@ -428,12 +426,8 @@ except argparse.ArgumentError:
|
|
|
428
426
|
/// Property that returns the coldkeypub file.
|
|
429
427
|
#[getter]
|
|
430
428
|
pub fn coldkeypub_file(&self) -> PyResult<Keyfile> {
|
|
431
|
-
// get home dir
|
|
432
|
-
let home = home_dir()
|
|
433
|
-
.ok_or_else(|| PyErr::new::<PyRuntimeError, _>("Failed to get user home directory."))?;
|
|
434
|
-
|
|
435
429
|
// concatenate wallet path
|
|
436
|
-
let wallet_path =
|
|
430
|
+
let wallet_path = self._path.join(&self.name);
|
|
437
431
|
|
|
438
432
|
// concatenate hotkey path
|
|
439
433
|
let coldkeypub_path = wallet_path.join("coldkeypub.txt");
|
|
@@ -828,7 +822,7 @@ except argparse.ArgumentError:
|
|
|
828
822
|
|
|
829
823
|
let keypair = Keypair::new(ss58_address, public_key, None, 42, None, 1)?;
|
|
830
824
|
|
|
831
|
-
self.set_coldkeypub(keypair,
|
|
825
|
+
self.set_coldkeypub(keypair, false, overwrite, py)?;
|
|
832
826
|
Ok(self.clone())
|
|
833
827
|
}
|
|
834
828
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|