From e046ae5a1c0c8eda4e1410ccac4f2419553fae82 Mon Sep 17 00:00:00 2001 From: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:50:52 +0200 Subject: [PATCH] Fix restore_from_stronghold_snapshot() with same source and target path (#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 --- .../actions/private-tangle/setup/action.yml | 5 + Cargo.lock | 6 +- bindings/nodejs/CHANGELOG.md | 6 ++ bindings/nodejs/package.json | 2 +- .../core/operations/stronghold_backup/mod.rs | 12 ++- sdk/tests/wallet/backup_restore.rs | 99 +++++++++++++++++++ 6 files changed, 123 insertions(+), 7 deletions(-) diff --git a/.github/actions/private-tangle/setup/action.yml b/.github/actions/private-tangle/setup/action.yml index 2504053375..7b0fbc4de4 100644 --- a/.github/actions/private-tangle/setup/action.yml +++ b/.github/actions/private-tangle/setup/action.yml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index 0191e7fa8d..dfd996edcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1880,7 +1880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.48.5", ] [[package]] @@ -2810,9 +2810,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.3" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring", diff --git a/bindings/nodejs/CHANGELOG.md b/bindings/nodejs/CHANGELOG.md index 5bece978d6..1f095c9b70 100644 --- a/bindings/nodejs/CHANGELOG.md +++ b/bindings/nodejs/CHANGELOG.md @@ -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 diff --git a/bindings/nodejs/package.json b/bindings/nodejs/package.json index cb52f6f006..97db771f1b 100644 --- a/bindings/nodejs/package.json +++ b/bindings/nodejs/package.json @@ -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", diff --git a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs index abfedfc1ad..dcf6aa5dee 100644 --- a/sdk/src/wallet/core/operations/stronghold_backup/mod.rs +++ b/sdk/src/wallet/core/operations/stronghold_backup/mod.rs @@ -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 @@ -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() { @@ -294,7 +298,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)?; + } // Set password to restored secret manager restored_secret_manager.set_password(stronghold_password).await?; diff --git a/sdk/tests/wallet/backup_restore.rs b/sdk/tests/wallet/backup_restore.rs index 663acd7744..648b28fc76 100644 --- a/sdk/tests/wallet/backup_restore.rs +++ b/sdk/tests/wallet/backup_restore.rs @@ -131,6 +131,105 @@ async fn backup_and_restore() -> Result<(), Box> { tear_down(storage_path) } +// Backup and restore with Stronghold and same path +#[ignore] +#[tokio::test] +async fn backup_and_restore_same_path() -> Result<(), Box> { + 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> {