update scanned keystores to importer type and model on wallet import
What changed, and why it matters
This commit fixes a wallet-import labeling bug. When a user imported a wallet file that had been exported from a hardware-wallet-style source, Sparrow was not correctly updating the keystore's type and model to match the importer. The patch makes the import process consistently set the source and device model, and only overwrites the default label rather than any custom label the user had set. There is no direct evidence this is a security vulnerability, but mislabeling a keystore could confuse users about which device controls their funds.
Treat as a routine bug-fix commit. Reviewers may want to verify that the new importScannedWallet() path is reached in all expected import scenarios and that custom labels are preserved, but no urgent security action is indicated.
Security signals we found
UI/data-labeling correctness fix
No cryptographic, network, or privilege changes
No input validation or parsing changes
Refactoring to reduce duplicated import logic
Evidence from the diff
The change refactors duplicated wallet-import logic in FileWalletKeystoreImportPane into a new importScannedWallet() helper. That helper now calls wallet.setName(), wallet.setDefaultPolicy(), and then, if the keystore source is SW_WATCH, updates the keystore label (only when it equals Keystore.DEFAULT_LABEL), sets source to HW_AIRGAPPED, and sets walletModel to the importer’s wallet model. FileImportPane’s existing keystore update is guarded so it only relabels default labels. The commit prevents custom labels from being overwritten and ensures scanned wallet keystores are tagged with the correct importer type/model.
Changed components
src/main/java/com/sparrowwallet/sparrow/control/FileImportPane.javasrc/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.javaWallet import flow for scanned/software-watch keystoresInspect captured patch +22 / −7
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileImportPane.java
index d165972..3571a34 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/FileImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/FileImportPane.java
@@ -203,7 +203,9 @@ public abstract class FileImportPane extends TitledDescriptionPane {
for(Wallet wallet : wallets) {
if(scriptType.equals(wallet.getScriptType()) && !wallet.getKeystores().isEmpty()) {
Keystore keystore = wallet.getKeystores().get(0);
- keystore.setLabel(importer.getName().replace(" Multisig", ""));
+ if(Keystore.DEFAULT_LABEL.equals(keystore.getLabel())) {
+ keystore.setLabel(importer.getName().replace(" Multisig", ""));
+ }
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
keystore.setWalletModel(importer.getWalletModel());
return keystore;
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java
index b938875..d5f101b 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/FileWalletKeystoreImportPane.java
@@ -7,6 +7,7 @@ import com.sparrowwallet.drongo.policy.Policy;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.ScriptType;
import com.sparrowwallet.drongo.wallet.Keystore;
+import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletImportEvent;
@@ -67,9 +68,7 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
if(types.size() == 1) {
Wallet wallet = wallets.stream().filter(w -> w.getPolicyType() == types.getFirst().policyType() && w.getScriptType() == types.getFirst().scriptType()).findFirst().orElseThrow(ImportException::new);
- wallet.setDefaultPolicy(Policy.getPolicy(wallet.getPolicyType(), wallet.getScriptType(), wallet.getKeystores(), null));
- wallet.setName(importer.getName());
- EventManager.get().post(new WalletImportEvent(wallet));
+ importScannedWallet(wallet);
return;
}
} else {
@@ -91,9 +90,7 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
if(wallets != null && !wallets.isEmpty()) {
Wallet wallet = wallets.stream().filter(w -> w.getPolicyType() == policyType && w.getScriptType() == scriptType).findFirst().orElseThrow(ImportException::new);
- wallet.setName(importer.getName());
- wallet.setDefaultPolicy(Policy.getPolicy(policyType, scriptType, wallet.getKeystores(), null));
- EventManager.get().post(new WalletImportEvent(wallet));
+ importScannedWallet(wallet);
} else {
ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
Keystore keystore = importer.getKeystore(policyType, scriptType, bais, password);
@@ -109,6 +106,22 @@ public class FileWalletKeystoreImportPane extends FileImportPane {
}
}
+ private void importScannedWallet(Wallet wallet) {
+ wallet.setName(importer.getName());
+ wallet.setDefaultPolicy(Policy.getPolicy(wallet.getPolicyType(), wallet.getScriptType(), wallet.getKeystores(), null));
+
+ Keystore keystore = wallet.getKeystores().getFirst();
+ if(keystore.getSource() == KeystoreSource.SW_WATCH) {
+ if(Keystore.DEFAULT_LABEL.equals(keystore.getLabel())) {
+ keystore.setLabel(importer.getName());
+ }
+ keystore.setSource(KeystoreSource.HW_AIRGAPPED);
+ keystore.setWalletModel(importer.getWalletModel());
+ }
+
+ EventManager.get().post(new WalletImportEvent(wallet));
+ }
+
private Node getScriptTypeEntry(List<PolicyAndScriptType> types) {
Label label = new Label("Type:");
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.