Skip to content

Commit

Permalink
Fix restore_from_stronghold_snapshot() with same source and target pa…
Browse files Browse the repository at this point in the history
…th (#2234)

* Fix restore_from_stronghold_snapshot() for the case when source and target path are the same

* Update rustls

* Unblock port 8084

* Compare canonicalized paths, replace used port 8084
  • Loading branch information
Thoralf-M authored Apr 22, 2024
1 parent 48126d2 commit e046ae5
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .github/actions/private-tangle/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ runs:
go-version-file: "iota-core/go.mod"
cache: false

- name: Replace port 8084 by 8087 as it's already used by Mono
shell: bash
run: sed -i 's#8084#8087#g' docker-compose.yml
working-directory: iota-core/tools/docker-network

- name: Setup private tangle
shell: bash
# setup-go sets the PATH for the correct version, but sudo uses a different PATH by default
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions bindings/nodejs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security -->

## 2.0.0-alpha.8 - 2024-04-22

### Fixed

- `Wallet::restoreFromStrongholdSnapshot()` with same source and target path;

## 2.0.0-alpha.7 - 2024-04-19

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion bindings/nodejs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@iota/sdk",
"version": "2.0.0-alpha.7",
"version": "2.0.0-alpha.8",
"description": "Node.js binding to the IOTA SDK library",
"main": "out/index.js",
"types": "out/index.d.ts",
Expand Down
12 changes: 9 additions & 3 deletions sdk/src/wallet/core/operations/stronghold_backup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ impl Wallet {
.map_err(|_| WalletError::Backup("invalid secret_manager"))?;

// Copy Stronghold file so the seed is available in the new location
fs::copy(backup_path, new_snapshot_path)?;
if backup_path.canonicalize()? != new_snapshot_path.canonicalize()? {
fs::copy(backup_path, new_snapshot_path)?;
}

if let SecretManager::Stronghold(stronghold) = &restored_secret_manager {
// Set password to restored secret manager
Expand All @@ -144,7 +146,9 @@ impl Wallet {
} else {
// If no secret manager data was in the backup, just copy the Stronghold file so the seed is available in
// the new location.
fs::copy(backup_path, new_snapshot_path)?;
if backup_path.canonicalize()? != new_snapshot_path.canonicalize()? {
fs::copy(backup_path, new_snapshot_path)?;
}
}

if ignore_if_bip_path_mismatch.is_none() {
Expand Down Expand Up @@ -294,7 +298,9 @@ impl Wallet<StrongholdSecretManager> {
.map_err(|_| WalletError::Backup("invalid secret_manager"))?;

// Copy Stronghold file so the seed is available in the new location
fs::copy(backup_path, new_snapshot_path)?;
if backup_path.canonicalize()? != new_snapshot_path.canonicalize()? {
fs::copy(backup_path, new_snapshot_path)?;
}

// Set password to restored secret manager
restored_secret_manager.set_password(stronghold_password).await?;
Expand Down
99 changes: 99 additions & 0 deletions sdk/tests/wallet/backup_restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,105 @@ async fn backup_and_restore() -> Result<(), Box<dyn std::error::Error>> {
tear_down(storage_path)
}

// Backup and restore with Stronghold and same path
#[ignore]
#[tokio::test]
async fn backup_and_restore_same_path() -> Result<(), Box<dyn std::error::Error>> {
iota_stronghold::engine::snapshot::try_set_encrypt_work_factor(0).unwrap();

let storage_path = "test-storage/backup_and_restore_same_path";
setup(storage_path)?;

let client_options = ClientOptions::new().with_node(NODE_LOCAL)?;

let stronghold_password = "some_hopefully_secure_password".to_owned();

// Create directory if not existing, because stronghold panics otherwise
std::fs::create_dir_all(storage_path).ok();
let stronghold = StrongholdSecretManager::builder()
.password(stronghold_password.clone())
.build("test-storage/backup_and_restore_same_path/1.stronghold")?;

stronghold.store_mnemonic(Mnemonic::from("inhale gorilla deny three celery song category owner lottery rent author wealth penalty crawl hobby obtain glad warm early rain clutch slab august bleak".to_string())).await.unwrap();

let wallet = Wallet::builder()
.with_secret_manager(SecretManager::Stronghold(stronghold))
.with_client_options(client_options.clone())
.with_bip_path(Bip44::new(SHIMMER_COIN_TYPE))
.with_storage_path("test-storage/backup_and_restore_same_path/1")
.finish()
.await?;

wallet
.backup_to_stronghold_snapshot(
PathBuf::from("test-storage/backup_and_restore_same_path/backup.stronghold"),
stronghold_password.clone(),
)
.await?;

// restore from backup

let stronghold = StrongholdSecretManager::builder()
.password(stronghold_password.clone())
.build("test-storage/backup_and_restore_same_path/backup.stronghold")?;

let restored_wallet = Wallet::builder()
.with_storage_path("test-storage/backup_and_restore_same_path/2")
.with_secret_manager(SecretManager::Stronghold(stronghold))
.with_client_options(ClientOptions::new().with_ignore_node_health().with_node(NODE_LOCAL)?)
// Build with a different coin type, to check if it gets replaced by the one from the backup
.with_bip_path(Bip44::new(IOTA_COIN_TYPE))
.finish()
.await?;

// Correct password works
restored_wallet
.restore_from_stronghold_snapshot(
PathBuf::from("test-storage/backup_and_restore_same_path/backup.stronghold"),
stronghold_password,
None,
None,
)
.await?;

// Validate restored data

// Restored coin type is used
assert_eq!(restored_wallet.bip_path().await.unwrap().coin_type, SHIMMER_COIN_TYPE);

// compare restored client options
let client_options = restored_wallet.client_options().await;
let node_dto = NodeDto::Node(Node::from(Url::parse(NODE_LOCAL).unwrap()));
assert!(client_options.node_manager_builder.nodes.contains(&node_dto));

assert_eq!(wallet.address().await.clone(), restored_wallet.address().await.clone());

// secret manager is the same
assert_eq!(
wallet
.secret_manager()
.read()
.await
.generate_ed25519_addresses(GetAddressesOptions {
coin_type: SHIMMER_COIN_TYPE,
range: 0..1,
..Default::default()
})
.await?,
restored_wallet
.secret_manager()
.read()
.await
.generate_ed25519_addresses(GetAddressesOptions {
coin_type: SHIMMER_COIN_TYPE,
range: 0..1,
..Default::default()
})
.await?,
);
tear_down(storage_path)
}

// // Backup and restore with Stronghold and MnemonicSecretManager
// #[tokio::test]
// async fn backup_and_restore_mnemonic_secret_manager() -> Result<(), WalletError> {
Expand Down

0 comments on commit e046ae5

Please sign in to comment.