attempt to import wallet file if open fails

This commit is contained in:
Craig Raw
2020-10-05 10:36:27 +02:00
parent 9e5937d2fe
commit f949bcc1cf
8 changed files with 146 additions and 35 deletions
@@ -773,6 +773,9 @@ public class AppController implements Initializable {
Wallet wallet = storage.loadWallet();
checkWalletNetwork(wallet);
restorePublicKeysFromSeed(wallet, null);
if(!wallet.isValid()) {
throw new IllegalStateException("Wallet file is not valid.");
}
Tab tab = addWalletTab(storage, wallet);
tabs.getSelectionModel().select(tab);
} else if(FileType.BINARY.equals(fileType)) {
@@ -804,8 +807,11 @@ public class AppController implements Initializable {
if(exception instanceof InvalidPasswordException) {
showErrorDialog("Invalid Password", "The wallet password was invalid.");
} else {
log.error("Error Opening Wallet", exception);
showErrorDialog("Error Opening Wallet", exception.getMessage());
if(!attemptImportWallet(file, password)) {
log.error("Error Opening Wallet", exception);
showErrorDialog("Error Opening Wallet", exception.getMessage());
}
password.clear();
}
});
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.START, "Decrypting wallet..."));
@@ -814,8 +820,10 @@ public class AppController implements Initializable {
throw new IOException("Unsupported file type");
}
} catch(Exception e) {
log.error("Error opening wallet", e);
showErrorDialog("Error Opening Wallet", e.getMessage());
if(!attemptImportWallet(file, null)) {
log.error("Error opening wallet", e);
showErrorDialog("Error Opening Wallet", e.getMessage());
}
}
}
@@ -872,35 +880,65 @@ public class AppController implements Initializable {
Optional<Wallet> optionalWallet = dlg.showAndWait();
if(optionalWallet.isPresent()) {
Wallet wallet = optionalWallet.get();
File walletFile = Storage.getWalletFile(wallet.getName());
addImportedWallet(wallet);
}
}
if(walletFile.exists()) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Existing wallet found");
alert.setHeaderText("Replace existing wallet?");
alert.setContentText("Wallet file " + wallet.getName() + " already exists");
Optional<ButtonType> result = alert.showAndWait();
if(result.isPresent() && result.get() == ButtonType.CANCEL) {
return;
private boolean attemptImportWallet(File file, SecureString password) {
List<WalletImport> walletImporters = List.of(new ColdcardSinglesig(), new ColdcardMultisig(), new Electrum(), new Specter());
for(WalletImport importer : walletImporters) {
try(FileInputStream inputStream = new FileInputStream(file)) {
if(importer.isEncrypted(file) && password == null) {
WalletPasswordDialog dlg = new WalletPasswordDialog(file.getName(), WalletPasswordDialog.PasswordRequirement.LOAD);
Optional<SecureString> optionalPassword = dlg.showAndWait();
if(optionalPassword.isPresent()) {
password = optionalPassword.get();
}
}
//Close existing wallet first if open
for(Iterator<Tab> iter = tabs.getTabs().iterator(); iter.hasNext(); ) {
Tab tab = iter.next();
TabData tabData = (TabData)tab.getUserData();
if(tabData.getType() == TabData.TabType.WALLET) {
WalletTabData walletTabData = (WalletTabData) tabData;
if(walletTabData.getStorage().getWalletFile().equals(walletFile)) {
iter.remove();
}
Wallet wallet = importer.importWallet(inputStream, password == null ? null: password.asString());
if(wallet.getName() == null) {
wallet.setName(file.getName());
}
addImportedWallet(wallet);
return true;
} catch(Exception e) {
//ignore
}
}
return false;
}
private void addImportedWallet(Wallet wallet) {
File walletFile = Storage.getWalletFile(wallet.getName());
if(walletFile.exists()) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Existing wallet found");
alert.setHeaderText("Replace existing wallet?");
alert.setContentText("Wallet file " + wallet.getName() + " already exists");
Optional<ButtonType> result = alert.showAndWait();
if(result.isPresent() && result.get() == ButtonType.CANCEL) {
return;
}
//Close existing wallet first if open
for(Iterator<Tab> iter = tabs.getTabs().iterator(); iter.hasNext(); ) {
Tab tab = iter.next();
TabData tabData = (TabData)tab.getUserData();
if(tabData.getType() == TabData.TabType.WALLET) {
WalletTabData walletTabData = (WalletTabData) tabData;
if(walletTabData.getStorage().getWalletFile().equals(walletFile)) {
iter.remove();
}
}
}
Storage storage = new Storage(walletFile);
Tab tab = addWalletTab(storage, wallet);
tabs.getSelectionModel().select(tab);
}
Storage storage = new Storage(walletFile);
Tab tab = addWalletTab(storage, wallet);
tabs.getSelectionModel().select(tab);
}
public void exportWallet(ActionEvent event) {
@@ -5,9 +5,12 @@ import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyDerivation;
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.drongo.wallet.WalletModel;
import java.io.File;
@@ -16,7 +19,7 @@ import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.Map;
public class ColdcardSinglesig implements KeystoreFileImport {
public class ColdcardSinglesig implements KeystoreFileImport, WalletImport {
@Override
public String getName() {
return "Coldcard";
@@ -77,6 +80,29 @@ public class ColdcardSinglesig implements KeystoreFileImport {
throw new ImportException("Correct derivation not found for script type: " + scriptType);
}
@Override
public String getWalletImportDescription() {
return getKeystoreImportDescription();
}
@Override
public Wallet importWallet(InputStream inputStream, String password) throws ImportException {
//Use default of P2WPKH
Keystore keystore = getKeystore(ScriptType.P2WPKH, inputStream, "");
Wallet wallet = new Wallet();
wallet.setPolicyType(PolicyType.SINGLE);
wallet.setScriptType(ScriptType.P2WPKH);
wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), null));
if(!wallet.isValid()) {
throw new ImportException("Wallet is in an inconsistent state.");
}
return wallet;
}
private static class ColdcardKeystore {
public String deriv;
public String name;
@@ -81,7 +81,7 @@ public class Storage {
return gsonBuilder.setPrettyPrinting().disableHtmlEscaping().create();
}
public Wallet loadWallet() throws IOException, MnemonicException {
public Wallet loadWallet() throws IOException {
Reader reader = new FileReader(walletFile);
Wallet wallet = gson.fromJson(reader, Wallet.class);
reader.close();
@@ -90,7 +90,7 @@ public class Storage {
return wallet;
}
public WalletAndKey loadWallet(CharSequence password) throws IOException, MnemonicException, StorageException {
public WalletAndKey loadWallet(CharSequence password) throws IOException, StorageException {
InputStream fileStream = new FileInputStream(walletFile);
ECKey encryptionKey = getEncryptionKey(password, fileStream);
@@ -461,11 +461,9 @@ public class Storage {
protected Task<WalletAndKey> createTask() {
return new Task<>() {
protected WalletAndKey call() throws IOException, StorageException, MnemonicException {
try {
return storage.loadWallet(password);
} finally {
password.clear();
}
WalletAndKey walletAndKey = storage.loadWallet(password);
password.clear();
return walletAndKey;
}
};
}