mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2025-01-26 02:11:10 +00:00
retrieve, store and use device registrations to avoid unncessary reregistration on ledger multisig wallets
This commit is contained in:
parent
95200c7143
commit
ee2f387cd5
10 changed files with 130 additions and 35 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 0df1f79e5c7e9fc1daa212c875c9da5dbcc0ee56
|
Subproject commit f67a2caf5379a6931040f3a9b0c9203e9bfc3f44
|
|
@ -16,11 +16,8 @@ import com.sparrowwallet.drongo.wallet.*;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.event.*;
|
import com.sparrowwallet.sparrow.event.*;
|
||||||
import com.sparrowwallet.sparrow.io.CardApi;
|
import com.sparrowwallet.sparrow.io.*;
|
||||||
import com.sparrowwallet.sparrow.io.Device;
|
|
||||||
import com.sparrowwallet.sparrow.io.Hwi;
|
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.io.CardAuthorizationException;
|
|
||||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
@ -778,10 +775,12 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
signButton.setDisable(false);
|
signButton.setDisable(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Hwi.SignPSBTService signPSBTService = new Hwi.SignPSBTService(device, passphrase.get(), psbt, OutputDescriptor.getOutputDescriptor(wallet), wallet.getFullName());
|
Hwi.SignPSBTService signPSBTService = new Hwi.SignPSBTService(device, passphrase.get(), psbt,
|
||||||
|
OutputDescriptor.getOutputDescriptor(wallet), wallet.getFullName(), getDeviceRegistration());
|
||||||
signPSBTService.setOnSucceeded(workerStateEvent -> {
|
signPSBTService.setOnSucceeded(workerStateEvent -> {
|
||||||
PSBT signedPsbt = signPSBTService.getValue();
|
PSBT signedPsbt = signPSBTService.getValue();
|
||||||
EventManager.get().post(new PSBTSignedEvent(psbt, signedPsbt));
|
EventManager.get().post(new PSBTSignedEvent(psbt, signedPsbt));
|
||||||
|
updateDeviceRegistrations(signPSBTService.getNewDeviceRegistrations());
|
||||||
});
|
});
|
||||||
signPSBTService.setOnFailed(workerStateEvent -> {
|
signPSBTService.setOnFailed(workerStateEvent -> {
|
||||||
setError("Signing Error", signPSBTService.getException().getMessage());
|
setError("Signing Error", signPSBTService.getException().getMessage());
|
||||||
|
@ -821,10 +820,11 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
|
|
||||||
private void displayAddress() {
|
private void displayAddress() {
|
||||||
Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(device, passphrase.get(), wallet.getScriptType(), outputDescriptor,
|
Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(device, passphrase.get(), wallet.getScriptType(), outputDescriptor,
|
||||||
OutputDescriptor.getOutputDescriptor(wallet), wallet.getFullName());
|
OutputDescriptor.getOutputDescriptor(wallet), wallet.getFullName(), getDeviceRegistration());
|
||||||
displayAddressService.setOnSucceeded(successEvent -> {
|
displayAddressService.setOnSucceeded(successEvent -> {
|
||||||
String address = displayAddressService.getValue();
|
String address = displayAddressService.getValue();
|
||||||
EventManager.get().post(new AddressDisplayedEvent(address));
|
EventManager.get().post(new AddressDisplayedEvent(address));
|
||||||
|
updateDeviceRegistrations(displayAddressService.getNewDeviceRegistrations());
|
||||||
});
|
});
|
||||||
displayAddressService.setOnFailed(failedEvent -> {
|
displayAddressService.setOnFailed(failedEvent -> {
|
||||||
setError("Could not display address", displayAddressService.getException().getMessage());
|
setError("Could not display address", displayAddressService.getException().getMessage());
|
||||||
|
@ -834,6 +834,26 @@ public class DevicePane extends TitledDescriptionPane {
|
||||||
displayAddressService.start();
|
displayAddressService.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] getDeviceRegistration() {
|
||||||
|
Optional<Keystore> optKeystore = wallet.getKeystores().stream()
|
||||||
|
.filter(keystore -> keystore.getKeyDerivation().getMasterFingerprint().equals(device.getFingerprint()) && keystore.getDeviceRegistration() != null).findFirst();
|
||||||
|
return optKeystore.map(Keystore::getDeviceRegistration).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDeviceRegistrations(Set<byte[]> newDeviceRegistrations) {
|
||||||
|
if(!newDeviceRegistrations.isEmpty()) {
|
||||||
|
List<Keystore> registrationKeystores = getDeviceRegistrationKeystores();
|
||||||
|
if(!registrationKeystores.isEmpty()) {
|
||||||
|
registrationKeystores.forEach(keystore -> keystore.setDeviceRegistration(newDeviceRegistrations.iterator().next()));
|
||||||
|
EventManager.get().post(new KeystoreDeviceRegistrationsChangedEvent(wallet, registrationKeystores));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Keystore> getDeviceRegistrationKeystores() {
|
||||||
|
return wallet.getKeystores().stream().filter(keystore -> keystore.getKeyDerivation().getMasterFingerprint().equals(device.getFingerprint())).toList();
|
||||||
|
}
|
||||||
|
|
||||||
private void signMessage() {
|
private void signMessage() {
|
||||||
if(device.isCard()) {
|
if(device.isCard()) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KeystoreDeviceRegistrationsChangedEvent extends WalletChangedEvent {
|
||||||
|
private final List<Keystore> changedKeystores;
|
||||||
|
|
||||||
|
public KeystoreDeviceRegistrationsChangedEvent(Wallet wallet, List<Keystore> changedKeystores) {
|
||||||
|
super(wallet);
|
||||||
|
this.changedKeystores = changedKeystores;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Keystore> getChangedKeystores() {
|
||||||
|
return changedKeystores;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,8 @@ public class Hwi {
|
||||||
|
|
||||||
private static boolean isPromptActive = false;
|
private static boolean isPromptActive = false;
|
||||||
|
|
||||||
|
private final Set<byte[]> newDeviceRegistrations = new HashSet<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
//deleteHwiDir();
|
//deleteHwiDir();
|
||||||
}
|
}
|
||||||
|
@ -161,7 +163,10 @@ public class Hwi {
|
||||||
|
|
||||||
isPromptActive = true;
|
isPromptActive = true;
|
||||||
Lark lark = getLark(passphrase, walletDescriptor, walletName, walletRegistration);
|
Lark lark = getLark(passphrase, walletDescriptor, walletName, walletRegistration);
|
||||||
return lark.displayAddress(device.getType(), device.getPath(), addressDescriptor);
|
String address = lark.displayAddress(device.getType(), device.getPath(), addressDescriptor);
|
||||||
|
newDeviceRegistrations.addAll(lark.getWalletRegistrations().values());
|
||||||
|
newDeviceRegistrations.remove(walletRegistration);
|
||||||
|
return address;
|
||||||
} catch(DeviceException e) {
|
} catch(DeviceException e) {
|
||||||
throw new DisplayAddressException(e.getMessage(), e);
|
throw new DisplayAddressException(e.getMessage(), e);
|
||||||
} catch(RuntimeException e) {
|
} catch(RuntimeException e) {
|
||||||
|
@ -192,7 +197,10 @@ public class Hwi {
|
||||||
try {
|
try {
|
||||||
isPromptActive = true;
|
isPromptActive = true;
|
||||||
Lark lark = getLark(passphrase, walletDescriptor, walletName, walletRegistration);
|
Lark lark = getLark(passphrase, walletDescriptor, walletName, walletRegistration);
|
||||||
return lark.signTransaction(device.getType(), device.getPath(), psbt);
|
PSBT signed = lark.signTransaction(device.getType(), device.getPath(), psbt);
|
||||||
|
newDeviceRegistrations.addAll(lark.getWalletRegistrations().values());
|
||||||
|
newDeviceRegistrations.remove(walletRegistration);
|
||||||
|
return signed;
|
||||||
} catch(DeviceException e) {
|
} catch(DeviceException e) {
|
||||||
throw new SignTransactionException(e.getMessage(), e);
|
throw new SignTransactionException(e.getMessage(), e);
|
||||||
} catch(RuntimeException e) {
|
} catch(RuntimeException e) {
|
||||||
|
@ -346,16 +354,7 @@ public class Hwi {
|
||||||
private final OutputDescriptor walletDescriptor;
|
private final OutputDescriptor walletDescriptor;
|
||||||
private final String walletName;
|
private final String walletName;
|
||||||
private final byte[] walletRegistration;
|
private final byte[] walletRegistration;
|
||||||
|
private final Set<byte[]> newDeviceRegistrations = new HashSet<>();
|
||||||
public DisplayAddressService(Device device, String passphrase, ScriptType scriptType, OutputDescriptor addressDescriptor, OutputDescriptor walletDescriptor, String walletName) {
|
|
||||||
this.device = device;
|
|
||||||
this.passphrase = passphrase;
|
|
||||||
this.scriptType = scriptType;
|
|
||||||
this.addressDescriptor = addressDescriptor;
|
|
||||||
this.walletDescriptor = walletDescriptor;
|
|
||||||
this.walletName = walletName;
|
|
||||||
this.walletRegistration = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DisplayAddressService(Device device, String passphrase, ScriptType scriptType, OutputDescriptor addressDescriptor, OutputDescriptor walletDescriptor, String walletName, byte[] walletRegistration) {
|
public DisplayAddressService(Device device, String passphrase, ScriptType scriptType, OutputDescriptor addressDescriptor, OutputDescriptor walletDescriptor, String walletName, byte[] walletRegistration) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
|
@ -367,12 +366,18 @@ public class Hwi {
|
||||||
this.walletRegistration = walletRegistration;
|
this.walletRegistration = walletRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<byte[]> getNewDeviceRegistrations() {
|
||||||
|
return newDeviceRegistrations;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Task<String> createTask() {
|
protected Task<String> createTask() {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
protected String call() throws DisplayAddressException {
|
protected String call() throws DisplayAddressException {
|
||||||
Hwi hwi = new Hwi();
|
Hwi hwi = new Hwi();
|
||||||
return hwi.displayAddress(device, passphrase, scriptType, addressDescriptor, walletDescriptor, walletName, walletRegistration);
|
String address = hwi.displayAddress(device, passphrase, scriptType, addressDescriptor, walletDescriptor, walletName, walletRegistration);
|
||||||
|
newDeviceRegistrations.addAll(hwi.newDeviceRegistrations);
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -453,15 +458,7 @@ public class Hwi {
|
||||||
private final OutputDescriptor walletDescriptor;
|
private final OutputDescriptor walletDescriptor;
|
||||||
private final String walletName;
|
private final String walletName;
|
||||||
private final byte[] walletRegistration;
|
private final byte[] walletRegistration;
|
||||||
|
private final Set<byte[]> newDeviceRegistrations = new HashSet<>();
|
||||||
public SignPSBTService(Device device, String passphrase, PSBT psbt, OutputDescriptor walletDescriptor, String walletName) {
|
|
||||||
this.device = device;
|
|
||||||
this.passphrase = passphrase;
|
|
||||||
this.psbt = psbt;
|
|
||||||
this.walletDescriptor = walletDescriptor;
|
|
||||||
this.walletName = walletName;
|
|
||||||
this.walletRegistration = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SignPSBTService(Device device, String passphrase, PSBT psbt, OutputDescriptor walletDescriptor, String walletName, byte[] walletRegistration) {
|
public SignPSBTService(Device device, String passphrase, PSBT psbt, OutputDescriptor walletDescriptor, String walletName, byte[] walletRegistration) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
|
@ -472,12 +469,18 @@ public class Hwi {
|
||||||
this.walletRegistration = walletRegistration;
|
this.walletRegistration = walletRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<byte[]> getNewDeviceRegistrations() {
|
||||||
|
return newDeviceRegistrations;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Task<PSBT> createTask() {
|
protected Task<PSBT> createTask() {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
protected PSBT call() throws SignTransactionException {
|
protected PSBT call() throws SignTransactionException {
|
||||||
Hwi hwi = new Hwi();
|
Hwi hwi = new Hwi();
|
||||||
return hwi.signPSBT(device, passphrase, psbt, walletDescriptor, walletName, walletRegistration);
|
PSBT signed = hwi.signPSBT(device, passphrase, psbt, walletDescriptor, walletName, walletRegistration);
|
||||||
|
newDeviceRegistrations.addAll(hwi.newDeviceRegistrations);
|
||||||
|
return signed;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,6 +355,13 @@ public class DbPersistence implements Persistence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!dirtyPersistables.registrationKeystores.isEmpty()) {
|
||||||
|
KeystoreDao keystoreDao = handle.attach(KeystoreDao.class);
|
||||||
|
for(Keystore keystore : dirtyPersistables.registrationKeystores) {
|
||||||
|
keystoreDao.updateDeviceRegistration(keystore.getDeviceRegistration(), keystore.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dirtyPersistablesMap.remove(wallet);
|
dirtyPersistablesMap.remove(wallet);
|
||||||
} finally {
|
} finally {
|
||||||
walletDao.setSchema(DEFAULT_SCHEMA);
|
walletDao.setSchema(DEFAULT_SCHEMA);
|
||||||
|
@ -792,6 +799,13 @@ public class DbPersistence implements Persistence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void keystoreDeviceRegistrationsChanged(KeystoreDeviceRegistrationsChangedEvent event) {
|
||||||
|
if(persistsFor(event.getWallet())) {
|
||||||
|
updateExecutor.execute(() -> dirtyPersistablesMap.computeIfAbsent(event.getWallet(), key -> new DirtyPersistables()).registrationKeystores.addAll(event.getChangedKeystores()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void walletWatchLastChanged(WalletWatchLastChangedEvent event) {
|
public void walletWatchLastChanged(WalletWatchLastChangedEvent event) {
|
||||||
if(persistsFor(event.getWallet())) {
|
if(persistsFor(event.getWallet())) {
|
||||||
|
@ -815,6 +829,7 @@ public class DbPersistence implements Persistence {
|
||||||
public final Map<Sha256Hash, UtxoMixData> removedUtxoMixes = new HashMap<>();
|
public final Map<Sha256Hash, UtxoMixData> removedUtxoMixes = new HashMap<>();
|
||||||
public final List<Keystore> labelKeystores = new ArrayList<>();
|
public final List<Keystore> labelKeystores = new ArrayList<>();
|
||||||
public final List<Keystore> encryptionKeystores = new ArrayList<>();
|
public final List<Keystore> encryptionKeystores = new ArrayList<>();
|
||||||
|
public final List<Keystore> registrationKeystores = new ArrayList<>();
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Dirty Persistables" +
|
return "Dirty Persistables" +
|
||||||
|
@ -834,7 +849,8 @@ public class DbPersistence implements Persistence {
|
||||||
"\nUTXO mixes changed:" + changedUtxoMixes +
|
"\nUTXO mixes changed:" + changedUtxoMixes +
|
||||||
"\nUTXO mixes removed:" + removedUtxoMixes +
|
"\nUTXO mixes removed:" + removedUtxoMixes +
|
||||||
"\nKeystore labels:" + labelKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList()) +
|
"\nKeystore labels:" + labelKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList()) +
|
||||||
"\nKeystore encryptions:" + encryptionKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList());
|
"\nKeystore encryptions:" + encryptionKeystores.stream().map(Keystore::getLabel).collect(Collectors.toList()) +
|
||||||
|
"\nKeystore registrations:" + registrationKeystores.stream().map(Keystore::getDeviceRegistration).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,16 @@ import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface KeystoreDao {
|
public interface KeystoreDao {
|
||||||
@SqlQuery("select keystore.id, keystore.label, keystore.source, keystore.walletModel, keystore.masterFingerprint, keystore.derivationPath, keystore.extendedPublicKey, keystore.externalPaymentCode, " +
|
@SqlQuery("select keystore.id, keystore.label, keystore.source, keystore.walletModel, keystore.masterFingerprint, keystore.derivationPath, keystore.extendedPublicKey, keystore.externalPaymentCode, keystore.deviceRegistration, " +
|
||||||
"masterPrivateExtendedKey.id, masterPrivateExtendedKey.privateKey, masterPrivateExtendedKey.chainCode, masterPrivateExtendedKey.initialisationVector, masterPrivateExtendedKey.encryptedBytes, masterPrivateExtendedKey.keySalt, masterPrivateExtendedKey.deriver, masterPrivateExtendedKey.crypter, " +
|
"masterPrivateExtendedKey.id, masterPrivateExtendedKey.privateKey, masterPrivateExtendedKey.chainCode, masterPrivateExtendedKey.initialisationVector, masterPrivateExtendedKey.encryptedBytes, masterPrivateExtendedKey.keySalt, masterPrivateExtendedKey.deriver, masterPrivateExtendedKey.crypter, " +
|
||||||
"seed.id, seed.type, seed.mnemonicString, seed.initialisationVector, seed.encryptedBytes, seed.keySalt, seed.deriver, seed.crypter, seed.needsPassphrase, seed.creationTimeSeconds " +
|
"seed.id, seed.type, seed.mnemonicString, seed.initialisationVector, seed.encryptedBytes, seed.keySalt, seed.deriver, seed.crypter, seed.needsPassphrase, seed.creationTimeSeconds " +
|
||||||
"from keystore left join masterPrivateExtendedKey on keystore.masterPrivateExtendedKey = masterPrivateExtendedKey.id left join seed on keystore.seed = seed.id where keystore.wallet = ? order by keystore.index asc")
|
"from keystore left join masterPrivateExtendedKey on keystore.masterPrivateExtendedKey = masterPrivateExtendedKey.id left join seed on keystore.seed = seed.id where keystore.wallet = ? order by keystore.index asc")
|
||||||
@RegisterRowMapper(KeystoreMapper.class)
|
@RegisterRowMapper(KeystoreMapper.class)
|
||||||
List<Keystore> getForWalletId(Long id);
|
List<Keystore> getForWalletId(Long id);
|
||||||
|
|
||||||
@SqlUpdate("insert into keystore (label, source, walletModel, masterFingerprint, derivationPath, extendedPublicKey, externalPaymentCode, masterPrivateExtendedKey, seed, wallet, index) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
@SqlUpdate("insert into keystore (label, source, walletModel, masterFingerprint, derivationPath, extendedPublicKey, externalPaymentCode, deviceRegistration, masterPrivateExtendedKey, seed, wallet, index) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
@GetGeneratedKeys("id")
|
@GetGeneratedKeys("id")
|
||||||
long insert(String label, int source, int walletModel, String masterFingerprint, String derivationPath, String extendedPublicKey, String externalPaymentCode, Long masterPrivateExtendedKey, Long seed, long wallet, int index);
|
long insert(String label, int source, int walletModel, String masterFingerprint, String derivationPath, String extendedPublicKey, String externalPaymentCode, byte[] deviceRegistration, Long masterPrivateExtendedKey, Long seed, long wallet, int index);
|
||||||
|
|
||||||
@SqlUpdate("insert into masterPrivateExtendedKey (privateKey, chainCode, initialisationVector, encryptedBytes, keySalt, deriver, crypter, creationTimeSeconds) values (?, ?, ?, ?, ?, ?, ?, ?)")
|
@SqlUpdate("insert into masterPrivateExtendedKey (privateKey, chainCode, initialisationVector, encryptedBytes, keySalt, deriver, crypter, creationTimeSeconds) values (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
@GetGeneratedKeys("id")
|
@GetGeneratedKeys("id")
|
||||||
|
@ -41,6 +41,9 @@ public interface KeystoreDao {
|
||||||
@SqlUpdate("update keystore set label = ? where id = ?")
|
@SqlUpdate("update keystore set label = ? where id = ?")
|
||||||
void updateLabel(String label, long id);
|
void updateLabel(String label, long id);
|
||||||
|
|
||||||
|
@SqlUpdate("update keystore set deviceRegistration = ? where id = ?")
|
||||||
|
void updateDeviceRegistration(byte[] deviceRegistration, long id);
|
||||||
|
|
||||||
default void addKeystores(Wallet wallet) {
|
default void addKeystores(Wallet wallet) {
|
||||||
for(int i = 0; i < wallet.getKeystores().size(); i++) {
|
for(int i = 0; i < wallet.getKeystores().size(); i++) {
|
||||||
Keystore keystore = wallet.getKeystores().get(i);
|
Keystore keystore = wallet.getKeystores().get(i);
|
||||||
|
@ -73,6 +76,7 @@ public interface KeystoreDao {
|
||||||
keystore.getKeyDerivation().getDerivationPath(),
|
keystore.getKeyDerivation().getDerivationPath(),
|
||||||
keystore.hasMasterPrivateKey() || wallet.isBip47() ? null : keystore.getExtendedPublicKey().toString(),
|
keystore.hasMasterPrivateKey() || wallet.isBip47() ? null : keystore.getExtendedPublicKey().toString(),
|
||||||
keystore.getExternalPaymentCode() == null ? null : keystore.getExternalPaymentCode().toString(),
|
keystore.getExternalPaymentCode() == null ? null : keystore.getExternalPaymentCode().toString(),
|
||||||
|
keystore.getDeviceRegistration(),
|
||||||
keystore.getMasterPrivateExtendedKey() == null ? null : keystore.getMasterPrivateExtendedKey().getId(),
|
keystore.getMasterPrivateExtendedKey() == null ? null : keystore.getMasterPrivateExtendedKey().getId(),
|
||||||
keystore.getSeed() == null ? null : keystore.getSeed().getId(), wallet.getId(), i);
|
keystore.getSeed() == null ? null : keystore.getSeed().getId(), wallet.getId(), i);
|
||||||
keystore.setId(id);
|
keystore.setId(id);
|
||||||
|
|
|
@ -25,6 +25,7 @@ public class KeystoreMapper implements RowMapper<Keystore> {
|
||||||
keystore.setKeyDerivation(new KeyDerivation(rs.getString("keystore.masterFingerprint"), rs.getString("keystore.derivationPath")));
|
keystore.setKeyDerivation(new KeyDerivation(rs.getString("keystore.masterFingerprint"), rs.getString("keystore.derivationPath")));
|
||||||
keystore.setExtendedPublicKey(rs.getString("keystore.extendedPublicKey") == null ? null : ExtendedKey.fromDescriptor(rs.getString("keystore.extendedPublicKey")));
|
keystore.setExtendedPublicKey(rs.getString("keystore.extendedPublicKey") == null ? null : ExtendedKey.fromDescriptor(rs.getString("keystore.extendedPublicKey")));
|
||||||
keystore.setExternalPaymentCode(rs.getString("keystore.externalPaymentCode") == null ? null : PaymentCode.fromString(rs.getString("keystore.externalPaymentCode")));
|
keystore.setExternalPaymentCode(rs.getString("keystore.externalPaymentCode") == null ? null : PaymentCode.fromString(rs.getString("keystore.externalPaymentCode")));
|
||||||
|
keystore.setDeviceRegistration(rs.getBytes("keystore.deviceRegistration"));
|
||||||
|
|
||||||
if(rs.getBytes("masterPrivateExtendedKey.privateKey") != null) {
|
if(rs.getBytes("masterPrivateExtendedKey.privateKey") != null) {
|
||||||
MasterPrivateExtendedKey masterPrivateExtendedKey = new MasterPrivateExtendedKey(rs.getBytes("masterPrivateExtendedKey.privateKey"), rs.getBytes("masterPrivateExtendedKey.chainCode"));
|
MasterPrivateExtendedKey masterPrivateExtendedKey = new MasterPrivateExtendedKey(rs.getBytes("masterPrivateExtendedKey.privateKey"), rs.getBytes("masterPrivateExtendedKey.chainCode"));
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.google.zxing.qrcode.QRCodeWriter;
|
||||||
import com.sparrowwallet.drongo.KeyPurpose;
|
import com.sparrowwallet.drongo.KeyPurpose;
|
||||||
import com.sparrowwallet.drongo.OutputDescriptor;
|
import com.sparrowwallet.drongo.OutputDescriptor;
|
||||||
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Keystore;
|
||||||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
@ -234,7 +235,10 @@ public class ReceiveController extends WalletFormController implements Initializ
|
||||||
} else {
|
} else {
|
||||||
Device actualDevice = possibleDevices.get(0);
|
Device actualDevice = possibleDevices.get(0);
|
||||||
Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(actualDevice, "", wallet.getScriptType(), addressDescriptor,
|
Hwi.DisplayAddressService displayAddressService = new Hwi.DisplayAddressService(actualDevice, "", wallet.getScriptType(), addressDescriptor,
|
||||||
OutputDescriptor.getOutputDescriptor(walletForm.getWallet()), walletForm.getWallet().getFullName());
|
OutputDescriptor.getOutputDescriptor(walletForm.getWallet()), walletForm.getWallet().getFullName(), getDeviceRegistration(actualDevice));
|
||||||
|
displayAddressService.setOnSucceeded(successEvent -> {
|
||||||
|
updateDeviceRegistrations(actualDevice, displayAddressService.getNewDeviceRegistrations());
|
||||||
|
});
|
||||||
displayAddressService.setOnFailed(failedEvent -> {
|
displayAddressService.setOnFailed(failedEvent -> {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
DeviceDisplayAddressDialog dlg = new DeviceDisplayAddressDialog(wallet, addressDescriptor);
|
DeviceDisplayAddressDialog dlg = new DeviceDisplayAddressDialog(wallet, addressDescriptor);
|
||||||
|
@ -252,6 +256,26 @@ public class ReceiveController extends WalletFormController implements Initializ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] getDeviceRegistration(Device device) {
|
||||||
|
Optional<Keystore> optKeystore = getWalletForm().getWallet().getKeystores().stream()
|
||||||
|
.filter(keystore -> keystore.getKeyDerivation().getMasterFingerprint().equals(device.getFingerprint()) && keystore.getDeviceRegistration() != null).findFirst();
|
||||||
|
return optKeystore.map(Keystore::getDeviceRegistration).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDeviceRegistrations(Device device, Set<byte[]> newDeviceRegistrations) {
|
||||||
|
if(!newDeviceRegistrations.isEmpty()) {
|
||||||
|
List<Keystore> registrationKeystores = getDeviceRegistrationKeystores(device);
|
||||||
|
if(!registrationKeystores.isEmpty()) {
|
||||||
|
registrationKeystores.forEach(keystore -> keystore.setDeviceRegistration(newDeviceRegistrations.iterator().next()));
|
||||||
|
EventManager.get().post(new KeystoreDeviceRegistrationsChangedEvent(getWalletForm().getWallet(), registrationKeystores));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Keystore> getDeviceRegistrationKeystores(Device device) {
|
||||||
|
return getWalletForm().getWallet().getKeystores().stream().filter(keystore -> keystore.getKeyDerivation().getMasterFingerprint().equals(device.getFingerprint())).toList();
|
||||||
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
if(currentEntry != null) {
|
if(currentEntry != null) {
|
||||||
label.textProperty().unbindBidirectional(currentEntry.labelProperty());
|
label.textProperty().unbindBidirectional(currentEntry.labelProperty());
|
||||||
|
|
|
@ -640,6 +640,13 @@ public class WalletForm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void keystoreDeviceRegistrationsChanged(KeystoreDeviceRegistrationsChangedEvent event) {
|
||||||
|
if(event.getWallet() == wallet) {
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new WalletDataChangedEvent(wallet)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void walletTabsClosed(WalletTabsClosedEvent event) {
|
public void walletTabsClosed(WalletTabsClosedEvent event) {
|
||||||
for(WalletTabData tabData : event.getClosedWalletTabData()) {
|
for(WalletTabData tabData : event.getClosedWalletTabData()) {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
alter table keystore add column deviceRegistration varbinary(32) after externalPaymentCode;
|
Loading…
Reference in a new issue