mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Add export feature for signed account age witness
This commit is contained in:
parent
2b6dd187c6
commit
ef81bde7f2
@ -381,6 +381,15 @@ public class AccountAgeWitnessService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getWitnessSignDate(AccountAgeWitness accountAgeWitness) {
|
||||||
|
List<Long> dates = signedWitnessService.getVerifiedWitnessDateList(accountAgeWitness);
|
||||||
|
if (dates.isEmpty()) {
|
||||||
|
return -1L;
|
||||||
|
} else {
|
||||||
|
return dates.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return -1 if not signed
|
// Return -1 if not signed
|
||||||
public long getWitnessSignAge(Offer offer, Date now) {
|
public long getWitnessSignAge(Offer offer, Date now) {
|
||||||
return findWitness(offer)
|
return findWitness(offer)
|
||||||
@ -951,4 +960,8 @@ public class AccountAgeWitnessService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFilteredWitness(AccountAgeWitness accountAgeWitness) {
|
||||||
|
return signedWitnessService.isFilteredWitness(accountAgeWitness);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import bisq.core.util.JsonUtil;
|
|||||||
|
|
||||||
import bisq.network.p2p.storage.P2PDataStorage;
|
import bisq.network.p2p.storage.P2PDataStorage;
|
||||||
|
|
||||||
|
import bisq.common.app.DevEnv;
|
||||||
import bisq.common.crypto.CryptoException;
|
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;
|
||||||
@ -41,11 +42,13 @@ 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;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -197,13 +200,37 @@ public class AccountAgeWitnessUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<String> exportAccount(AccountAgeWitnessService accountAgeWitnessService,
|
static class SignedWitnessDto {
|
||||||
PaymentAccount account,
|
private final String profileId;
|
||||||
KeyRing keyRing,
|
private final String hashAsHex;
|
||||||
String profileId) {
|
private final long accountAgeWitnessDate;
|
||||||
|
private final long witnessSignDate;
|
||||||
|
private final String pubKeyBase64;
|
||||||
|
private final String signatureBase64;
|
||||||
|
|
||||||
|
public SignedWitnessDto(String profileId,
|
||||||
|
String hashAsHex,
|
||||||
|
long accountAgeWitnessDate,
|
||||||
|
long witnessSignDate,
|
||||||
|
String pubKeyBase64,
|
||||||
|
String signatureBase64) {
|
||||||
|
this.profileId = profileId;
|
||||||
|
this.hashAsHex = hashAsHex;
|
||||||
|
this.accountAgeWitnessDate = accountAgeWitnessDate;
|
||||||
|
this.witnessSignDate = witnessSignDate;
|
||||||
|
this.pubKeyBase64 = pubKeyBase64;
|
||||||
|
this.signatureBase64 = signatureBase64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<String> signAccountAgeAndBisq2ProfileId(AccountAgeWitnessService accountAgeWitnessService,
|
||||||
|
PaymentAccount account,
|
||||||
|
KeyRing keyRing,
|
||||||
|
String profileId) {
|
||||||
return accountAgeWitnessService.findWitness(account.getPaymentAccountPayload(), keyRing.getPubKeyRing())
|
return accountAgeWitnessService.findWitness(account.getPaymentAccountPayload(), keyRing.getPubKeyRing())
|
||||||
.map(accountAgeWitness -> {
|
.map(accountAgeWitness -> {
|
||||||
try {
|
try {
|
||||||
|
checkArgument(!accountAgeWitnessService.isFilteredWitness(accountAgeWitness), "Invalid account age witness");
|
||||||
String hashAsHex = Hex.encode(accountAgeWitness.getHash());
|
String hashAsHex = Hex.encode(accountAgeWitness.getHash());
|
||||||
String message = profileId + hashAsHex + accountAgeWitness.getDate();
|
String message = profileId + hashAsHex + accountAgeWitness.getDate();
|
||||||
KeyPair signatureKeyPair = keyRing.getSignatureKeyPair();
|
KeyPair signatureKeyPair = keyRing.getSignatureKeyPair();
|
||||||
@ -220,4 +247,36 @@ public class AccountAgeWitnessUtils {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<String> signSignedWitnessAndBisq2ProfileId(AccountAgeWitnessService accountAgeWitnessService,
|
||||||
|
PaymentAccount account,
|
||||||
|
KeyRing keyRing,
|
||||||
|
String profileId) {
|
||||||
|
return accountAgeWitnessService.findWitness(account.getPaymentAccountPayload(), keyRing.getPubKeyRing())
|
||||||
|
.map(accountAgeWitness -> {
|
||||||
|
try {
|
||||||
|
checkArgument(!accountAgeWitnessService.isFilteredWitness(accountAgeWitness), "Invalid account age witness");
|
||||||
|
long witnessSignDate = accountAgeWitnessService.getWitnessSignDate(accountAgeWitness);
|
||||||
|
long ageInDays = (System.currentTimeMillis() - witnessSignDate) / TimeUnit.DAYS.toMillis(1);
|
||||||
|
if (!DevEnv.isDevMode()) {
|
||||||
|
checkArgument(witnessSignDate > 0, "Account is not signed yet");
|
||||||
|
checkArgument(ageInDays > 60, "Account must have been signed at least 61 days ago");
|
||||||
|
}
|
||||||
|
String hashAsHex = Hex.encode(accountAgeWitness.getHash());
|
||||||
|
String message = profileId + hashAsHex + accountAgeWitness.getDate() + witnessSignDate;
|
||||||
|
KeyPair signatureKeyPair = keyRing.getSignatureKeyPair();
|
||||||
|
String signatureBase64 = Sig.sign(signatureKeyPair.getPrivate(), message);
|
||||||
|
String pubKeyBase64 = Base64.getEncoder().encodeToString(Sig.getPublicKeyBytes(signatureKeyPair.getPublic()));
|
||||||
|
SignedWitnessDto dto = new SignedWitnessDto(profileId,
|
||||||
|
hashAsHex,
|
||||||
|
accountAgeWitness.getDate(),
|
||||||
|
witnessSignDate,
|
||||||
|
pubKeyBase64,
|
||||||
|
signatureBase64);
|
||||||
|
return JsonUtil.objectToJson(dto);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1819,8 +1819,12 @@ 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=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 \
|
account.fiat.exportAccountAge.popup=Your 'account age' and Bisq 2 profile ID got signed and the data is copied \
|
||||||
to the clipboard.\n\
|
to the clipboard.\n\n\This is the data in json format:\n\n\{0}\n\n\
|
||||||
|
Go back to Bisq 2 and follow the instructions there.
|
||||||
|
account.fiat.signedWitness=Export signed witness for Bisq 2
|
||||||
|
account.fiat.signedWitness.popup=Your 'signed account age witness' and Bisq 2 profile ID got signed and the data is copied \
|
||||||
|
to the clipboard.\n\n\This is the data in json format:\n\n\{0}\n\n\
|
||||||
Go back to Bisq 2 and follow the instructions there.
|
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
|
||||||
|
@ -510,35 +510,65 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
|
|||||||
GridPane.setRowSpan(accountTitledGroupBg, paymentMethodForm.getRowSpan());
|
GridPane.setRowSpan(accountTitledGroupBg, paymentMethodForm.getRowSpan());
|
||||||
|
|
||||||
Button exportAccountAgeButton = new AutoTooltipButton(Res.get("account.fiat.exportAccountAge"));
|
Button exportAccountAgeButton = new AutoTooltipButton(Res.get("account.fiat.exportAccountAge"));
|
||||||
exportAccountAgeButton.setOnAction(event -> onExportAccountAge(paymentMethodForm.getPaymentAccount()));
|
exportAccountAgeButton.setOnAction(event -> onExportAccountAgeForBisq2(paymentMethodForm.getPaymentAccount()));
|
||||||
exportAccountAgeButton.setMaxWidth(Double.MAX_VALUE);
|
exportAccountAgeButton.setMaxWidth(Double.MAX_VALUE);
|
||||||
HBox.setHgrow(exportAccountAgeButton, Priority.ALWAYS);
|
HBox.setHgrow(exportAccountAgeButton, Priority.ALWAYS);
|
||||||
|
|
||||||
|
Button signedWitnessButton = new AutoTooltipButton(Res.get("account.fiat.signedWitness"));
|
||||||
|
signedWitnessButton.setOnAction(event -> onExportSignedWitnessForBisq2(paymentMethodForm.getPaymentAccount()));
|
||||||
|
signedWitnessButton.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
HBox.setHgrow(signedWitnessButton, Priority.ALWAYS);
|
||||||
|
|
||||||
|
|
||||||
HBox hBox = (HBox) cancelButton.getParent();
|
HBox hBox = (HBox) cancelButton.getParent();
|
||||||
hBox.getChildren().add(exportAccountAgeButton);
|
hBox.getChildren().addAll(exportAccountAgeButton, signedWitnessButton);
|
||||||
|
|
||||||
model.onSelectAccount(current);
|
model.onSelectAccount(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExportAccountAge(PaymentAccount paymentAccount) {
|
private void onExportAccountAgeForBisq2(PaymentAccount paymentAccount) {
|
||||||
|
String prefix = "BISQ2_ACCOUNT_AGE:";
|
||||||
|
try {
|
||||||
|
String profileId = getProfileIdFromClipBoard(prefix);
|
||||||
|
AccountAgeWitnessUtils.signAccountAgeAndBisq2ProfileId(accountAgeWitnessService, paymentAccount, keyRing, profileId)
|
||||||
|
.ifPresent(json -> {
|
||||||
|
Utilities.copyToClipboard(prefix + json);
|
||||||
|
new Popup().information(Res.get("account.fiat.exportAccountAge.popup", json))
|
||||||
|
.width(900).show();
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
String error = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
|
||||||
|
new Popup().warning(error).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onExportSignedWitnessForBisq2(PaymentAccount paymentAccount) {
|
||||||
|
String prefix = "BISQ2_SIGNED_WITNESS:";
|
||||||
|
try {
|
||||||
|
String profileId = getProfileIdFromClipBoard(prefix);
|
||||||
|
AccountAgeWitnessUtils.signSignedWitnessAndBisq2ProfileId(accountAgeWitnessService, paymentAccount, keyRing, profileId)
|
||||||
|
.ifPresent(json -> {
|
||||||
|
Utilities.copyToClipboard(prefix + json);
|
||||||
|
new Popup().information(Res.get("account.fiat.signedWitness.popup", json))
|
||||||
|
.width(900).show();
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
String error = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
|
||||||
|
new Popup().warning(error).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getProfileIdFromClipBoard(String prefix) {
|
||||||
String clipboardText = Clipboard.getSystemClipboard().getString();
|
String clipboardText = Clipboard.getSystemClipboard().getString();
|
||||||
String prefix = "BISQ2_ACCOUNT_AGE_REQUEST:";
|
|
||||||
if (clipboardText != null && clipboardText.startsWith(prefix)) {
|
if (clipboardText != null && clipboardText.startsWith(prefix)) {
|
||||||
String profileId = clipboardText.replace(prefix, "");
|
String profileId = clipboardText.replace(prefix, "");
|
||||||
if (profileId.length() == 40) {
|
if (profileId.length() == 40) {
|
||||||
try {
|
Hex.decode(profileId);
|
||||||
Hex.decode(profileId);
|
return 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.");
|
throw new RuntimeException("Clipboard text not in expected format. " + clipboardText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user