mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
add support for satschip nfc card
This commit is contained in:
parent
4de6bd5e83
commit
74a551ed01
13 changed files with 61 additions and 18 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit d255913654b29a33c772dead9b66721c70fe7950
|
Subproject commit 3dbcdfcf4ebeb478d6da28f17f5dc74dba244fe1
|
|
@ -62,7 +62,7 @@ public abstract class CardApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CardApi getCardApi(WalletModel walletModel, String pin) throws CardException {
|
public static CardApi getCardApi(WalletModel walletModel, String pin) throws CardException {
|
||||||
if(walletModel == WalletModel.TAPSIGNER || walletModel == WalletModel.SATSCARD) {
|
if(walletModel == WalletModel.TAPSIGNER || walletModel == WalletModel.SATSCHIP || walletModel == WalletModel.SATSCARD) {
|
||||||
return new CkCardApi(walletModel, pin);
|
return new CkCardApi(walletModel, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ public class CardStatus extends CardResponse {
|
||||||
String ver;
|
String ver;
|
||||||
BigInteger birth;
|
BigInteger birth;
|
||||||
boolean tapsigner;
|
boolean tapsigner;
|
||||||
|
boolean satschip;
|
||||||
List<BigInteger> path;
|
List<BigInteger> path;
|
||||||
BigInteger num_backups;
|
BigInteger num_backups;
|
||||||
List<BigInteger> slots;
|
List<BigInteger> slots;
|
||||||
|
@ -24,7 +25,7 @@ public class CardStatus extends CardResponse {
|
||||||
boolean testnet;
|
boolean testnet;
|
||||||
|
|
||||||
public boolean isInitialized() {
|
public boolean isInitialized() {
|
||||||
return (getCardType() == WalletModel.TAPSIGNER && path != null) || (getCardType() == WalletModel.SATSCARD && addr != null);
|
return ((getCardType() == WalletModel.TAPSIGNER || getCardType() == WalletModel.SATSCHIP) && path != null) || (getCardType() == WalletModel.SATSCARD && addr != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIdentifier() {
|
public String getIdentifier() {
|
||||||
|
@ -42,11 +43,11 @@ public class CardStatus extends CardResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean requiresBackup() {
|
public boolean requiresBackup() {
|
||||||
return num_backups == null || num_backups.intValue() == 0;
|
return !satschip && (num_backups == null || num_backups.intValue() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WalletModel getCardType() {
|
public WalletModel getCardType() {
|
||||||
return tapsigner ? WalletModel.TAPSIGNER : WalletModel.SATSCARD;
|
return satschip ? WalletModel.SATSCHIP : (tapsigner ? WalletModel.TAPSIGNER : WalletModel.SATSCARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentSlot() {
|
public int getCurrentSlot() {
|
||||||
|
@ -72,6 +73,7 @@ public class CardStatus extends CardResponse {
|
||||||
", ver='" + ver + '\'' +
|
", ver='" + ver + '\'' +
|
||||||
", birth=" + birth +
|
", birth=" + birth +
|
||||||
", tapsigner=" + tapsigner +
|
", tapsigner=" + tapsigner +
|
||||||
|
", satschip=" + satschip +
|
||||||
", path=" + path +
|
", path=" + path +
|
||||||
", num_backups=" + num_backups +
|
", num_backups=" + num_backups +
|
||||||
", slots=" + slots +
|
", slots=" + slots +
|
||||||
|
|
|
@ -32,10 +32,6 @@ public class CkCardApi extends CardApi {
|
||||||
private final CardProtocol cardProtocol;
|
private final CardProtocol cardProtocol;
|
||||||
private String cvc;
|
private String cvc;
|
||||||
|
|
||||||
public CkCardApi(String cvc) throws CardException {
|
|
||||||
this(WalletModel.TAPSIGNER, cvc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CkCardApi(WalletModel cardType, String cvc) throws CardException {
|
public CkCardApi(WalletModel cardType, String cvc) throws CardException {
|
||||||
this.cardType = cardType;
|
this.cardType = cardType;
|
||||||
this.cardProtocol = new CardProtocol();
|
this.cardProtocol = new CardProtocol();
|
||||||
|
@ -137,6 +133,8 @@ public class CkCardApi extends CardApi {
|
||||||
public Service<Void> getInitializationService(byte[] entropy, StringProperty messageProperty) {
|
public Service<Void> getInitializationService(byte[] entropy, StringProperty messageProperty) {
|
||||||
if(cardType == WalletModel.TAPSIGNER) {
|
if(cardType == WalletModel.TAPSIGNER) {
|
||||||
return new CardImportPane.CardInitializationService(new Tapsigner(), cvc, entropy, messageProperty);
|
return new CardImportPane.CardInitializationService(new Tapsigner(), cvc, entropy, messageProperty);
|
||||||
|
} else if(cardType == WalletModel.SATSCHIP) {
|
||||||
|
return new CardImportPane.CardInitializationService(new Satschip(), cvc, entropy, messageProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CardInitializationService(entropy, messageProperty);
|
return new CardInitializationService(entropy, messageProperty);
|
||||||
|
@ -144,6 +142,10 @@ public class CkCardApi extends CardApi {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty) {
|
public Service<Keystore> getImportService(List<ChildNumber> derivation, StringProperty messageProperty) {
|
||||||
|
if(cardType == WalletModel.SATSCHIP) {
|
||||||
|
return new CardImportPane.CardImportService(new Satschip(), cvc, derivation, messageProperty);
|
||||||
|
}
|
||||||
|
|
||||||
return new CardImportPane.CardImportService(new Tapsigner(), cvc, derivation, messageProperty);
|
return new CardImportPane.CardImportService(new Tapsigner(), cvc, derivation, messageProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,11 +157,11 @@ public class CkCardApi extends CardApi {
|
||||||
ExtendedKey derivedXpubkey = ExtendedKey.fromDescriptor(Base58.encodeChecked(derivedXpub.xpub));
|
ExtendedKey derivedXpubkey = ExtendedKey.fromDescriptor(Base58.encodeChecked(derivedXpub.xpub));
|
||||||
|
|
||||||
Keystore keystore = new Keystore();
|
Keystore keystore = new Keystore();
|
||||||
keystore.setLabel(WalletModel.TAPSIGNER.toDisplayString());
|
keystore.setLabel(cardType.toDisplayString());
|
||||||
keystore.setKeyDerivation(keyDerivation);
|
keystore.setKeyDerivation(keyDerivation);
|
||||||
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
|
keystore.setSource(KeystoreSource.HW_AIRGAPPED);
|
||||||
keystore.setExtendedPublicKey(derivedXpubkey);
|
keystore.setExtendedPublicKey(derivedXpubkey);
|
||||||
keystore.setWalletModel(WalletModel.TAPSIGNER);
|
keystore.setWalletModel(cardType);
|
||||||
|
|
||||||
return keystore;
|
return keystore;
|
||||||
}
|
}
|
||||||
|
@ -404,7 +406,7 @@ public class CkCardApi extends CardApi {
|
||||||
@Override
|
@Override
|
||||||
protected PSBT call() throws Exception {
|
protected PSBT call() throws Exception {
|
||||||
CardStatus cardStatus = getStatus();
|
CardStatus cardStatus = getStatus();
|
||||||
if(cardStatus.getCardType() != WalletModel.TAPSIGNER) {
|
if(cardStatus.getCardType() != WalletModel.TAPSIGNER && cardStatus.getCardType() != WalletModel.SATSCHIP) {
|
||||||
throw new IllegalStateException("Please use a " + WalletModel.TAPSIGNER.toDisplayString() + " to sign transactions.");
|
throw new IllegalStateException("Please use a " + WalletModel.TAPSIGNER.toDisplayString() + " to sign transactions.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +467,7 @@ public class CkCardApi extends CardApi {
|
||||||
@Override
|
@Override
|
||||||
protected String call() throws Exception {
|
protected String call() throws Exception {
|
||||||
CardStatus cardStatus = getStatus();
|
CardStatus cardStatus = getStatus();
|
||||||
if(cardStatus.getCardType() != WalletModel.TAPSIGNER) {
|
if(cardStatus.getCardType() != WalletModel.TAPSIGNER && cardStatus.getCardType() != WalletModel.SATSCHIP) {
|
||||||
throw new IllegalStateException("Please use a " + WalletModel.TAPSIGNER.toDisplayString() + " to sign messages.");
|
throw new IllegalStateException("Please use a " + WalletModel.TAPSIGNER.toDisplayString() + " to sign messages.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.sparrowwallet.sparrow.io.ckcard;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||||
|
|
||||||
|
public class Satschip extends Tapsigner {
|
||||||
|
@Override
|
||||||
|
public String getKeystoreImportDescription(int account) {
|
||||||
|
return "Import the keystore from your Satschip by placing it on the card reader.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Satschip";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WalletModel getWalletModel() {
|
||||||
|
return WalletModel.SATSCHIP;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ public class Tapsigner implements KeystoreCardImport {
|
||||||
public boolean isInitialized() throws CardException {
|
public boolean isInitialized() throws CardException {
|
||||||
CkCardApi cardApi = null;
|
CkCardApi cardApi = null;
|
||||||
try {
|
try {
|
||||||
cardApi = new CkCardApi(null);
|
cardApi = new CkCardApi(getWalletModel(), null);
|
||||||
return cardApi.isInitialized();
|
return cardApi.isInitialized();
|
||||||
} finally {
|
} finally {
|
||||||
if(cardApi != null) {
|
if(cardApi != null) {
|
||||||
|
@ -37,7 +37,7 @@ public class Tapsigner implements KeystoreCardImport {
|
||||||
|
|
||||||
CkCardApi cardApi = null;
|
CkCardApi cardApi = null;
|
||||||
try {
|
try {
|
||||||
cardApi = new CkCardApi(pin);
|
cardApi = new CkCardApi(getWalletModel(), pin);
|
||||||
CardStatus cardStatus = cardApi.getStatus();
|
CardStatus cardStatus = cardApi.getStatus();
|
||||||
if(cardStatus.isInitialized()) {
|
if(cardStatus.isInitialized()) {
|
||||||
throw new IllegalStateException("Card is already initialized.");
|
throw new IllegalStateException("Card is already initialized.");
|
||||||
|
@ -63,7 +63,7 @@ public class Tapsigner implements KeystoreCardImport {
|
||||||
|
|
||||||
CkCardApi cardApi = null;
|
CkCardApi cardApi = null;
|
||||||
try {
|
try {
|
||||||
cardApi = new CkCardApi(pin);
|
cardApi = new CkCardApi(getWalletModel(), pin);
|
||||||
CardStatus cardStatus = cardApi.getStatus();
|
CardStatus cardStatus = cardApi.getStatus();
|
||||||
if(!cardStatus.isInitialized()) {
|
if(!cardStatus.isInitialized()) {
|
||||||
throw new IllegalStateException("Card is not initialized.");
|
throw new IllegalStateException("Card is not initialized.");
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.sparrowwallet.sparrow.control.CardImportPane;
|
||||||
import com.sparrowwallet.sparrow.control.FileKeystoreImportPane;
|
import com.sparrowwallet.sparrow.control.FileKeystoreImportPane;
|
||||||
import com.sparrowwallet.sparrow.control.TitledDescriptionPane;
|
import com.sparrowwallet.sparrow.control.TitledDescriptionPane;
|
||||||
import com.sparrowwallet.sparrow.io.*;
|
import com.sparrowwallet.sparrow.io.*;
|
||||||
|
import com.sparrowwallet.sparrow.io.ckcard.Satschip;
|
||||||
import com.sparrowwallet.sparrow.io.ckcard.Tapsigner;
|
import com.sparrowwallet.sparrow.io.ckcard.Tapsigner;
|
||||||
import com.sparrowwallet.sparrow.io.satochip.Satochip;
|
import com.sparrowwallet.sparrow.io.satochip.Satochip;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
@ -39,7 +40,7 @@ public class HwAirgappedController extends KeystoreImportDetailController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<KeystoreCardImport> cardImporters = List.of(new Tapsigner(), new Satochip());
|
List<KeystoreCardImport> cardImporters = List.of(new Tapsigner(), new Satochip(), new Satschip());
|
||||||
for(KeystoreCardImport importer : cardImporters) {
|
for(KeystoreCardImport importer : cardImporters) {
|
||||||
if(!importer.isDeprecated() || Config.get().isShowDeprecatedImportExport()) {
|
if(!importer.isDeprecated() || Config.get().isShowDeprecatedImportExport()) {
|
||||||
CardImportPane importPane = new CardImportPane(getMasterController().getWallet(), importer, getMasterController().getRequiredDerivation());
|
CardImportPane importPane = new CardImportPane(getMasterController().getWallet(), importer, getMasterController().getRequiredDerivation());
|
||||||
|
|
|
@ -493,7 +493,7 @@ public class KeystoreController extends WalletFormController implements Initiali
|
||||||
log.error("Error communicating with card", e);
|
log.error("Error communicating with card", e);
|
||||||
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
|
AppServices.showErrorDialog("Error communicating with card", e.getMessage());
|
||||||
});
|
});
|
||||||
ServiceProgressDialog serviceProgressDialog = new ServiceProgressDialog("Authentication Delay", "Waiting for authentication delay to clear...", "/image/tapsigner.png", authDelayService);
|
ServiceProgressDialog serviceProgressDialog = new ServiceProgressDialog("Authentication Delay", "Waiting for authentication delay to clear...", "/image/" + cardApi.getCardType().getType() + ".png", authDelayService);
|
||||||
serviceProgressDialog.initOwner(cardServiceButtons.getScene().getWindow());
|
serviceProgressDialog.initOwner(cardServiceButtons.getScene().getWindow());
|
||||||
AppServices.moveToActiveWindowScreen(serviceProgressDialog);
|
AppServices.moveToActiveWindowScreen(serviceProgressDialog);
|
||||||
authDelayService.start();
|
authDelayService.start();
|
||||||
|
|
9
src/main/resources/image/satschip-icon-invert.svg
Normal file
9
src/main/resources/image/satschip-icon-invert.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15px" height="15px" viewBox="0 0 15 15" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(88.627451%,88.627451%,88.627451%);fill-opacity:1;" d="M 2.605469 2.015625 L 12.394531 2.015625 C 12.722656 2.015625 12.984375 2.277344 12.984375 2.605469 L 12.984375 12.394531 C 12.984375 12.722656 12.722656 12.984375 12.394531 12.984375 L 2.605469 12.984375 C 2.277344 12.984375 2.015625 12.722656 2.015625 12.394531 L 2.015625 2.605469 C 2.015625 2.277344 2.277344 2.015625 2.605469 2.015625 Z M 2.605469 2.015625 "/>
|
||||||
|
<path style="fill:none;stroke-width:80;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(17.254902%,17.254902%,17.254902%);stroke-opacity:1;stroke-miterlimit:10;" d="M 825.78125 308.072917 C 805.364583 371.145833 784.21875 434.21875 755.416667 494.010417 C 744.84375 515.885417 732.083333 537.03125 718.958333 557.447917 C 702.916667 582.239583 678.854167 592.8125 649.6875 590.989583 C 644.947917 590.625 639.479167 590.625 634.739583 591.354167 C 615.78125 593.541667 603.020833 604.114583 594.635417 620.520833 C 587.34375 634.739583 584.0625 650.052083 582.239583 665.729167 C 579.322917 692.34375 580.78125 718.229167 588.4375 743.75 C 591.71875 755.052083 596.822917 765.625 604.84375 774.010417 C 614.322917 784.21875 625.989583 788.59375 639.479167 789.322917 C 647.864583 789.6875 656.25 789.322917 664.270833 789.6875 C 687.96875 790.78125 704.375 803.541667 718.229167 821.40625 C 737.552083 846.927083 751.40625 875.729167 764.166667 905.260417 C 788.59375 959.947917 807.916667 1016.822917 826.510417 1073.697917 " transform="matrix(0.0107143,0,0,0.0107143,0,0)"/>
|
||||||
|
<path style="fill:none;stroke-width:50;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(17.254902%,17.254902%,17.254902%);stroke-opacity:1;stroke-miterlimit:10;" d="M 699.635417 302.239583 L 699.635417 1077.708333 " transform="matrix(0.0107143,0,0,0.0107143,0,0)"/>
|
||||||
|
<path style="fill:none;stroke-width:50;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(17.254902%,17.254902%,17.254902%);stroke-opacity:1;stroke-miterlimit:10;" d="M 316.822917 690.520833 L 1083.541667 690.520833 " transform="matrix(0.0107143,0,0,0.0107143,0,0)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
9
src/main/resources/image/satschip-icon.svg
Normal file
9
src/main/resources/image/satschip-icon.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15px" height="15px" viewBox="0 0 15 15" version="1.1">
|
||||||
|
<g id="surface1">
|
||||||
|
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(23.137255%,23.137255%,23.137255%);fill-opacity:1;" d="M 2.605469 2.015625 L 12.394531 2.015625 C 12.722656 2.015625 12.984375 2.277344 12.984375 2.605469 L 12.984375 12.394531 C 12.984375 12.722656 12.722656 12.984375 12.394531 12.984375 L 2.605469 12.984375 C 2.277344 12.984375 2.015625 12.722656 2.015625 12.394531 L 2.015625 2.605469 C 2.015625 2.277344 2.277344 2.015625 2.605469 2.015625 Z M 2.605469 2.015625 "/>
|
||||||
|
<path style="fill:none;stroke-width:80;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(88.627451%,88.627451%,88.627451%);stroke-opacity:1;stroke-miterlimit:10;" d="M 825.78125 308.072917 C 805.364583 371.145833 784.21875 434.21875 755.416667 494.010417 C 744.84375 515.885417 732.083333 537.03125 718.958333 557.447917 C 702.916667 582.239583 678.854167 592.8125 649.6875 590.989583 C 644.947917 590.625 639.479167 590.625 634.739583 591.354167 C 615.78125 593.541667 603.020833 604.114583 594.635417 620.520833 C 587.34375 634.739583 584.0625 650.052083 582.239583 665.729167 C 579.322917 692.34375 580.78125 718.229167 588.4375 743.75 C 591.71875 755.052083 596.822917 765.625 604.84375 774.010417 C 614.322917 784.21875 625.989583 788.59375 639.479167 789.322917 C 647.864583 789.6875 656.25 789.322917 664.270833 789.6875 C 687.96875 790.78125 704.375 803.541667 718.229167 821.40625 C 737.552083 846.927083 751.40625 875.729167 764.166667 905.260417 C 788.59375 959.947917 807.916667 1016.822917 826.510417 1073.697917 " transform="matrix(0.0107143,0,0,0.0107143,0,0)"/>
|
||||||
|
<path style="fill:none;stroke-width:50;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(88.627451%,88.627451%,88.627451%);stroke-opacity:1;stroke-miterlimit:10;" d="M 699.635417 302.239583 L 699.635417 1077.708333 " transform="matrix(0.0107143,0,0,0.0107143,0,0)"/>
|
||||||
|
<path style="fill:none;stroke-width:50;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(88.627451%,88.627451%,88.627451%);stroke-opacity:1;stroke-miterlimit:10;" d="M 316.822917 690.520833 L 1083.541667 690.520833 " transform="matrix(0.0107143,0,0,0.0107143,0,0)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
BIN
src/main/resources/image/satschip.png
Normal file
BIN
src/main/resources/image/satschip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 852 B |
BIN
src/main/resources/image/satschip@2x.png
Normal file
BIN
src/main/resources/image/satschip@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
src/main/resources/image/satschip@3x.png
Normal file
BIN
src/main/resources/image/satschip@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Loading…
Reference in a new issue