Add export feature for account age

This commit is contained in:
chimp1984 2022-07-25 20:50:43 +02:00
parent 2628eea9db
commit 2b6dd187c6
No known key found for this signature in database
GPG Key ID: 9801B4EC591F90E3
5 changed files with 103 additions and 6 deletions

View File

@ -287,7 +287,7 @@ public class AccountAgeWitnessService {
} }
public Optional<AccountAgeWitness> findWitness(PaymentAccountPayload paymentAccountPayload, public Optional<AccountAgeWitness> findWitness(PaymentAccountPayload paymentAccountPayload,
PubKeyRing pubKeyRing) { PubKeyRing pubKeyRing) {
if (paymentAccountPayload == null) { if (paymentAccountPayload == null) {
return Optional.empty(); return Optional.empty();
} }

View File

@ -19,17 +19,25 @@ package bisq.core.account.witness;
import bisq.core.account.sign.SignedWitness; import bisq.core.account.sign.SignedWitness;
import bisq.core.account.sign.SignedWitnessService; import bisq.core.account.sign.SignedWitnessService;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.trade.model.bisq_v1.Trade; import bisq.core.trade.model.bisq_v1.Trade;
import bisq.core.util.JsonUtil;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.common.crypto.CryptoException;
import bisq.common.crypto.Hash; import bisq.common.crypto.Hash;
import bisq.common.crypto.KeyRing; import bisq.common.crypto.KeyRing;
import bisq.common.crypto.PubKeyRing; import bisq.common.crypto.PubKeyRing;
import bisq.common.crypto.Sig;
import bisq.common.util.Hex;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import java.security.KeyPair;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.Collection; import java.util.Collection;
import java.util.Optional; import java.util.Optional;
import java.util.Stack; import java.util.Stack;
@ -168,4 +176,48 @@ public class AccountAgeWitnessUtils {
accountAgeWitnessService.tradeAmountIsSufficient(trade.getAmount()), accountAgeWitnessService.tradeAmountIsSufficient(trade.getAmount()),
isSignWitnessTrade); isSignWitnessTrade);
} }
static class AccountAgeWitnessDto {
private final String profileId;
private final String hashAsHex;
private final long date;
private final String pubKeyBase64;
private final String signatureBase64;
public AccountAgeWitnessDto(String profileId,
String hashAsHex,
long date,
String pubKeyBase64,
String signatureBase64) {
this.profileId = profileId;
this.hashAsHex = hashAsHex;
this.date = date;
this.pubKeyBase64 = pubKeyBase64;
this.signatureBase64 = signatureBase64;
}
}
public static Optional<String> exportAccount(AccountAgeWitnessService accountAgeWitnessService,
PaymentAccount account,
KeyRing keyRing,
String profileId) {
return accountAgeWitnessService.findWitness(account.getPaymentAccountPayload(), keyRing.getPubKeyRing())
.map(accountAgeWitness -> {
try {
String hashAsHex = Hex.encode(accountAgeWitness.getHash());
String message = profileId + hashAsHex + accountAgeWitness.getDate();
KeyPair signatureKeyPair = keyRing.getSignatureKeyPair();
String signatureBase64 = Sig.sign(signatureKeyPair.getPrivate(), message);
String pubKeyBase64 = Base64.getEncoder().encodeToString(Sig.getPublicKeyBytes(signatureKeyPair.getPublic()));
AccountAgeWitnessDto dto = new AccountAgeWitnessDto(profileId,
hashAsHex,
accountAgeWitness.getDate(),
pubKeyBase64,
signatureBase64);
return JsonUtil.objectToJson(dto);
} catch (CryptoException e) {
throw new RuntimeException(e);
}
});
}
} }

View File

@ -1818,7 +1818,10 @@ providing cryptographic proof to the mediator or refund agent.\n\n\
If you do not understand these requirements, do not trade L-BTC on Bisq. If you do not understand these requirements, do not trade L-BTC on Bisq.
account.fiat.yourFiatAccounts=Your national currency accounts account.fiat.yourFiatAccounts=Your national currency accounts
account.fiat.exportAccountAge=Export account age for Bisq 2
account.fiat.exportAccountAge.popup=Your account age and Bisq 2 profile ID got signed and the data is copied \
to the clipboard.\n\
Go back to Bisq 2 and follow the instructions there.
account.backup.title=Backup wallet account.backup.title=Backup wallet
account.backup.location=Backup location account.backup.location=Backup location
account.backup.selectLocation=Select backup location account.backup.selectLocation=Select backup location

View File

@ -18,6 +18,7 @@
package bisq.desktop.main.account.content.fiataccounts; package bisq.desktop.main.account.content.fiataccounts;
import bisq.desktop.common.view.FxmlView; import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.TitledGroupBg; import bisq.desktop.components.TitledGroupBg;
import bisq.desktop.components.paymentmethods.AchTransferForm; import bisq.desktop.components.paymentmethods.AchTransferForm;
import bisq.desktop.components.paymentmethods.AdvancedCashForm; import bisq.desktop.components.paymentmethods.AdvancedCashForm;
@ -100,6 +101,7 @@ import bisq.desktop.util.validation.UpholdValidator;
import bisq.desktop.util.validation.WeChatPayValidator; import bisq.desktop.util.validation.WeChatPayValidator;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.account.witness.AccountAgeWitnessUtils;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.offer.OfferRestrictions; import bisq.core.offer.OfferRestrictions;
import bisq.core.payment.AmazonGiftCardAccount; import bisq.core.payment.AmazonGiftCardAccount;
@ -120,6 +122,8 @@ import bisq.core.util.FormattingUtils;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
import bisq.common.config.Config; import bisq.common.config.Config;
import bisq.common.crypto.KeyRing;
import bisq.common.util.Hex;
import bisq.common.util.Tuple2; import bisq.common.util.Tuple2;
import bisq.common.util.Tuple3; import bisq.common.util.Tuple3;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
@ -135,7 +139,10 @@ import javafx.scene.control.Button;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ListView; import javafx.scene.control.ListView;
import javafx.scene.input.Clipboard;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -157,6 +164,7 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
private final BICValidator bicValidator; private final BICValidator bicValidator;
private final CapitualValidator capitualValidator; private final CapitualValidator capitualValidator;
private final LengthValidator inputValidator; private final LengthValidator inputValidator;
private final KeyRing keyRing;
private final UpholdValidator upholdValidator; private final UpholdValidator upholdValidator;
private final MoneyBeamValidator moneyBeamValidator; private final MoneyBeamValidator moneyBeamValidator;
private final PopmoneyValidator popmoneyValidator; private final PopmoneyValidator popmoneyValidator;
@ -208,12 +216,14 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
AdvancedCashValidator advancedCashValidator, AdvancedCashValidator advancedCashValidator,
TransferwiseValidator transferwiseValidator, TransferwiseValidator transferwiseValidator,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
KeyRing keyRing,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) { @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
super(model, accountAgeWitnessService); super(model, accountAgeWitnessService);
this.bicValidator = bicValidator; this.bicValidator = bicValidator;
this.capitualValidator = capitualValidator; this.capitualValidator = capitualValidator;
this.inputValidator = inputValidator; this.inputValidator = inputValidator;
this.keyRing = keyRing;
this.inputValidator.setMaxLength(100); // restrict general field entry length this.inputValidator.setMaxLength(100); // restrict general field entry length
this.inputValidator.setMinLength(2); this.inputValidator.setMinLength(2);
this.upholdValidator = upholdValidator; this.upholdValidator = upholdValidator;
@ -296,9 +306,9 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
} }
new Popup().information(Res.get(limitsInfoKey, new Popup().information(Res.get(limitsInfoKey,
initialLimit, initialLimit,
formatter.formatCoinWithCode(maxTradeLimitSecondMonth), formatter.formatCoinWithCode(maxTradeLimitSecondMonth),
formatter.formatCoinWithCode(maxTradeLimitAsCoin))) formatter.formatCoinWithCode(maxTradeLimitAsCoin)))
.width(700) .width(700)
.closeButtonText(Res.get("shared.cancel")) .closeButtonText(Res.get("shared.cancel"))
.actionButtonText(Res.get("shared.iUnderstand")) .actionButtonText(Res.get("shared.iUnderstand"))
@ -490,6 +500,7 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
Res.get("shared.deleteAccount"), Res.get("shared.deleteAccount"),
Res.get("shared.cancel") Res.get("shared.cancel")
); );
Button updateButton = tuple.first; Button updateButton = tuple.first;
updateButton.setOnAction(event -> onUpdateAccount(paymentMethodForm.getPaymentAccount())); updateButton.setOnAction(event -> onUpdateAccount(paymentMethodForm.getPaymentAccount()));
Button deleteAccountButton = tuple.second; Button deleteAccountButton = tuple.second;
@ -497,10 +508,39 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
Button cancelButton = tuple.third; Button cancelButton = tuple.third;
cancelButton.setOnAction(event -> onCancelSelectedAccount(paymentMethodForm.getPaymentAccount())); cancelButton.setOnAction(event -> onCancelSelectedAccount(paymentMethodForm.getPaymentAccount()));
GridPane.setRowSpan(accountTitledGroupBg, paymentMethodForm.getRowSpan()); GridPane.setRowSpan(accountTitledGroupBg, paymentMethodForm.getRowSpan());
Button exportAccountAgeButton = new AutoTooltipButton(Res.get("account.fiat.exportAccountAge"));
exportAccountAgeButton.setOnAction(event -> onExportAccountAge(paymentMethodForm.getPaymentAccount()));
exportAccountAgeButton.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(exportAccountAgeButton, Priority.ALWAYS);
HBox hBox = (HBox) cancelButton.getParent();
hBox.getChildren().add(exportAccountAgeButton);
model.onSelectAccount(current); model.onSelectAccount(current);
} }
} }
private void onExportAccountAge(PaymentAccount paymentAccount) {
String clipboardText = Clipboard.getSystemClipboard().getString();
String prefix = "BISQ2_ACCOUNT_AGE_REQUEST:";
if (clipboardText != null && clipboardText.startsWith(prefix)) {
String profileId = clipboardText.replace(prefix, "");
if (profileId.length() == 40) {
try {
Hex.decode(profileId);
AccountAgeWitnessUtils.exportAccount(accountAgeWitnessService, paymentAccount, keyRing, profileId)
.ifPresent(json -> {
Utilities.copyToClipboard(json);
new Popup().information(Res.get("account.fiat.exportAccountAge.popup")).show();
});
return;
} catch (Throwable ignore) {
}
}
}
log.warn("Clipboard text not in expected format.");
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Utils // Utils

View File

@ -843,7 +843,9 @@ public class GUIUtil {
return true; return true;
} }
public static boolean canCreateOrTakeOfferOrShowPopup(User user, Navigation navigation, @Nullable TradeCurrency currency) { public static boolean canCreateOrTakeOfferOrShowPopup(User user,
Navigation navigation,
@Nullable TradeCurrency currency) {
if (currency != null && currency.getCode().equals("BSQ")) { if (currency != null && currency.getCode().equals("BSQ")) {
return true; return true;
} }