mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Add signed witness filter (#4124)
* Add signed witness filter - Add a filter to pubkeys used in AccountAgeWitness signing - Fix inverted arbitrator signing of initial account age witnesses from disputes - Add test to verify that signed witness filter works - Add test to verify that the arbitrator signing was fixed * Fix codacy complaints * Prevent NullPointerException during toggle group initialization * Add scrollbar to filter window * Format test class Co-authored-by: Christoph Atteneder <christoph.atteneder@gmail.com>
This commit is contained in:
parent
aeda234ef1
commit
09141eba92
@ -18,6 +18,7 @@
|
||||
package bisq.core.account.sign;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||
import bisq.core.user.User;
|
||||
|
||||
@ -34,6 +35,7 @@ import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -46,6 +48,7 @@ import java.security.SignatureException;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@ -60,7 +63,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class SignedWitnessService {
|
||||
public static final long SIGNER_AGE_DAYS = 30;
|
||||
public static final long SIGNER_AGE = SIGNER_AGE_DAYS * ChronoUnit.DAYS.getDuration().toMillis();
|
||||
private static final long SIGNER_AGE = SIGNER_AGE_DAYS * ChronoUnit.DAYS.getDuration().toMillis();
|
||||
static final Coin MINIMUM_TRADE_AMOUNT_FOR_SIGNING = Coin.parseCoin("0.0025");
|
||||
|
||||
private final KeyRing keyRing;
|
||||
@ -69,6 +72,7 @@ public class SignedWitnessService {
|
||||
private final User user;
|
||||
|
||||
private final Map<P2PDataStorage.ByteArray, SignedWitness> signedWitnessMap = new HashMap<>();
|
||||
private final FilterManager filterManager;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
@ -80,11 +84,13 @@ public class SignedWitnessService {
|
||||
ArbitratorManager arbitratorManager,
|
||||
SignedWitnessStorageService signedWitnessStorageService,
|
||||
AppendOnlyDataStoreService appendOnlyDataStoreService,
|
||||
User user) {
|
||||
User user,
|
||||
FilterManager filterManager) {
|
||||
this.keyRing = keyRing;
|
||||
this.p2PService = p2PService;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.user = user;
|
||||
this.filterManager = filterManager;
|
||||
|
||||
// We need to add that early (before onAllServicesInitialized) as it will be used at startup.
|
||||
appendOnlyDataStoreService.addService(signedWitnessStorageService);
|
||||
@ -131,8 +137,13 @@ public class SignedWitnessService {
|
||||
|
||||
/**
|
||||
* List of dates as long when accountAgeWitness was signed
|
||||
*
|
||||
* Witnesses that were added but are no longer considered signed won't be shown
|
||||
*/
|
||||
public List<Long> getVerifiedWitnessDateList(AccountAgeWitness accountAgeWitness) {
|
||||
if (!isSignedAccountAgeWitness(accountAgeWitness)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return getSignedWitnessSet(accountAgeWitness).stream()
|
||||
.filter(this::verifySignature)
|
||||
.map(SignedWitness::getDate)
|
||||
@ -159,6 +170,26 @@ public class SignedWitnessService {
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
public boolean isFilteredWitness(AccountAgeWitness accountAgeWitness) {
|
||||
return getSignedWitnessSet(accountAgeWitness).stream()
|
||||
.map(SignedWitness::getWitnessOwnerPubKey)
|
||||
.anyMatch(ownerPubKey -> filterManager.isSignerPubKeyBanned(Utils.HEX.encode(ownerPubKey)));
|
||||
}
|
||||
|
||||
public String ownerPubKey(AccountAgeWitness accountAgeWitness) {
|
||||
return getSignedWitnessSet(accountAgeWitness).stream()
|
||||
.map(signedWitness -> Utils.HEX.encode(signedWitness.getWitnessOwnerPubKey()))
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Set<SignedWitness> getSignedWitnessSetByOwnerPubKey(byte[] ownerPubKey) {
|
||||
return signedWitnessMap.values().stream()
|
||||
.filter(e -> Arrays.equals(e.getWitnessOwnerPubKey(), ownerPubKey))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
// Arbitrators sign with EC key
|
||||
public void signAccountAgeWitness(Coin tradeAmount,
|
||||
AccountAgeWitness accountAgeWitness,
|
||||
@ -322,6 +353,9 @@ public class SignedWitnessService {
|
||||
private boolean isValidSignerWitnessInternal(SignedWitness signedWitness,
|
||||
long childSignedWitnessDateMillis,
|
||||
Stack<P2PDataStorage.ByteArray> excludedPubKeys) {
|
||||
if (filterManager.isSignerPubKeyBanned(Utils.HEX.encode(signedWitness.getWitnessOwnerPubKey()))) {
|
||||
return false;
|
||||
}
|
||||
if (!verifySignature(signedWitness)) {
|
||||
return false;
|
||||
}
|
||||
@ -373,6 +407,7 @@ public class SignedWitnessService {
|
||||
if (!signedWitnessMap.containsKey(signedWitness.getHashAsByteArray())) {
|
||||
log.info("broadcast signed witness {}", signedWitness.toString());
|
||||
p2PService.addPersistableNetworkPayload(signedWitness, false);
|
||||
addToMap(signedWitness);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
import bisq.core.support.dispute.DisputeResult;
|
||||
import bisq.core.support.dispute.arbitration.TraderDataItem;
|
||||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.protocol.TradingPeer;
|
||||
import bisq.core.user.User;
|
||||
@ -54,9 +55,12 @@ import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -96,15 +100,25 @@ public class AccountAgeWitnessService {
|
||||
ARBITRATOR(Res.get("offerbook.timeSinceSigning.info.arbitrator")),
|
||||
PEER_INITIAL(Res.get("offerbook.timeSinceSigning.info.peer")),
|
||||
PEER_LIMIT_LIFTED(Res.get("offerbook.timeSinceSigning.info.peerLimitLifted")),
|
||||
PEER_SIGNER(Res.get("offerbook.timeSinceSigning.info.signer"));
|
||||
PEER_SIGNER(Res.get("offerbook.timeSinceSigning.info.signer")),
|
||||
BANNED(Res.get("offerbook.timeSinceSigning.info.banned"));
|
||||
|
||||
private String presentation;
|
||||
private String hash = "";
|
||||
|
||||
SignState(String presentation) {
|
||||
this.presentation = presentation;
|
||||
}
|
||||
|
||||
public SignState addHash(String hash) {
|
||||
this.hash = hash;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
if (!hash.isEmpty()) { // Only showing in DEBUG mode
|
||||
return presentation + " " + hash;
|
||||
}
|
||||
return presentation;
|
||||
}
|
||||
|
||||
@ -187,7 +201,8 @@ public class AccountAgeWitnessService {
|
||||
});
|
||||
}
|
||||
|
||||
private void addToMap(AccountAgeWitness accountAgeWitness) {
|
||||
@VisibleForTesting
|
||||
public void addToMap(AccountAgeWitness accountAgeWitness) {
|
||||
accountAgeWitnessMap.putIfAbsent(accountAgeWitness.getHashAsByteArray(), accountAgeWitness);
|
||||
}
|
||||
|
||||
@ -202,11 +217,18 @@ public class AccountAgeWitnessService {
|
||||
p2PService.addPersistableNetworkPayload(accountAgeWitness, false);
|
||||
}
|
||||
|
||||
public byte[] getPeerAccountAgeWitnessHash(Trade trade) {
|
||||
return findTradePeerWitness(trade)
|
||||
.map(accountAgeWitness -> accountAgeWitness.getHash())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private byte[] getAccountInputDataWithSalt(PaymentAccountPayload paymentAccountPayload) {
|
||||
return Utilities.concatenateByteArrays(paymentAccountPayload.getAgeWitnessInputData(), paymentAccountPayload.getSalt());
|
||||
}
|
||||
|
||||
private AccountAgeWitness getNewWitness(PaymentAccountPayload paymentAccountPayload, PubKeyRing pubKeyRing) {
|
||||
@VisibleForTesting
|
||||
public AccountAgeWitness getNewWitness(PaymentAccountPayload paymentAccountPayload, PubKeyRing pubKeyRing) {
|
||||
byte[] accountInputDataWithSalt = getAccountInputDataWithSalt(paymentAccountPayload);
|
||||
byte[] hash = Hash.getSha256Ripemd160hash(Utilities.concatenateByteArrays(accountInputDataWithSalt,
|
||||
pubKeyRing.getSignaturePubKeyBytes()));
|
||||
@ -623,7 +645,8 @@ public class AccountAgeWitnessService {
|
||||
}
|
||||
|
||||
// Arbitrator signing
|
||||
public List<TraderDataItem> getTraderPaymentAccounts(long safeDate, PaymentMethod paymentMethod,
|
||||
public List<TraderDataItem> getTraderPaymentAccounts(long safeDate,
|
||||
PaymentMethod paymentMethod,
|
||||
List<Dispute> disputes) {
|
||||
return disputes.stream()
|
||||
.filter(dispute -> dispute.getContract().getPaymentMethodId().equals(paymentMethod.getId()))
|
||||
@ -648,11 +671,16 @@ public class AccountAgeWitnessService {
|
||||
filterManager.isPeersPaymentAccountDataAreBanned(dispute.getContract().getBuyerPaymentAccountPayload(),
|
||||
new PaymentAccountFilter[1]) ||
|
||||
filterManager.isPeersPaymentAccountDataAreBanned(dispute.getContract().getSellerPaymentAccountPayload(),
|
||||
new PaymentAccountFilter[1]);
|
||||
new PaymentAccountFilter[1]) ||
|
||||
filterManager.isSignerPubKeyBanned(
|
||||
Utils.HEX.encode(dispute.getContract().getBuyerPubKeyRing().getSignaturePubKeyBytes())) ||
|
||||
filterManager.isSignerPubKeyBanned(
|
||||
Utils.HEX.encode(dispute.getContract().getSellerPubKeyRing().getSignaturePubKeyBytes()));
|
||||
return !isFiltered;
|
||||
}
|
||||
|
||||
private boolean hasChargebackRisk(Dispute dispute) {
|
||||
@VisibleForTesting
|
||||
public boolean hasChargebackRisk(Dispute dispute) {
|
||||
return chargeBackRisk.hasChargebackRisk(dispute.getContract().getPaymentMethodId(),
|
||||
dispute.getContract().getOfferPayload().getCurrencyCode());
|
||||
}
|
||||
@ -677,14 +705,14 @@ public class AccountAgeWitnessService {
|
||||
buyerPaymentAccountPaload,
|
||||
witness,
|
||||
tradeAmount,
|
||||
sellerPubKeyRing.getSignaturePubKey()))
|
||||
buyerPubKeyRing.getSignaturePubKey()))
|
||||
.orElse(null);
|
||||
TraderDataItem sellerData = findWitness(sellerPaymentAccountPaload, sellerPubKeyRing)
|
||||
.map(witness -> new TraderDataItem(
|
||||
sellerPaymentAccountPaload,
|
||||
witness,
|
||||
tradeAmount,
|
||||
buyerPubKeyRing.getSignaturePubKey()))
|
||||
sellerPubKeyRing.getSignaturePubKey()))
|
||||
.orElse(null);
|
||||
return Stream.of(buyerData, sellerData);
|
||||
}
|
||||
@ -722,19 +750,25 @@ public class AccountAgeWitnessService {
|
||||
}
|
||||
|
||||
public SignState getSignState(AccountAgeWitness accountAgeWitness) {
|
||||
// Add hash to sign state info when running in debug mode
|
||||
String hash = log.isDebugEnabled() ? Utilities.bytesAsHexString(accountAgeWitness.getHash()) + "\n" +
|
||||
signedWitnessService.ownerPubKey(accountAgeWitness) : "";
|
||||
if (signedWitnessService.isFilteredWitness(accountAgeWitness)) {
|
||||
return SignState.BANNED.addHash(hash);
|
||||
}
|
||||
if (signedWitnessService.isSignedByArbitrator(accountAgeWitness)) {
|
||||
return SignState.ARBITRATOR;
|
||||
return SignState.ARBITRATOR.addHash(hash);
|
||||
} else {
|
||||
final long accountSignAge = getWitnessSignAge(accountAgeWitness, new Date());
|
||||
switch (getAccountAgeCategory(accountSignAge)) {
|
||||
case TWO_MONTHS_OR_MORE:
|
||||
case ONE_TO_TWO_MONTHS:
|
||||
return SignState.PEER_SIGNER;
|
||||
return SignState.PEER_SIGNER.addHash(hash);
|
||||
case LESS_ONE_MONTH:
|
||||
return SignState.PEER_INITIAL;
|
||||
return SignState.PEER_INITIAL.addHash(hash);
|
||||
case UNVERIFIED:
|
||||
default:
|
||||
return SignState.UNSIGNED;
|
||||
return SignState.UNSIGNED.addHash(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,10 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
@Nullable
|
||||
private final List<String> refundAgents;
|
||||
|
||||
// added in v1.2.x
|
||||
@Nullable
|
||||
private final List<String> bannedSignerPubKeys;
|
||||
|
||||
public Filter(List<String> bannedOfferIds,
|
||||
List<String> bannedNodeAddress,
|
||||
List<PaymentAccountFilter> bannedPaymentAccounts,
|
||||
@ -115,7 +119,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
@Nullable String disableDaoBelowVersion,
|
||||
@Nullable String disableTradeBelowVersion,
|
||||
@Nullable List<String> mediators,
|
||||
@Nullable List<String> refundAgents) {
|
||||
@Nullable List<String> refundAgents,
|
||||
@Nullable List<String> bannedSignerPubKeys) {
|
||||
this.bannedOfferIds = bannedOfferIds;
|
||||
this.bannedNodeAddress = bannedNodeAddress;
|
||||
this.bannedPaymentAccounts = bannedPaymentAccounts;
|
||||
@ -131,6 +136,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
this.disableTradeBelowVersion = disableTradeBelowVersion;
|
||||
this.mediators = mediators;
|
||||
this.refundAgents = refundAgents;
|
||||
this.bannedSignerPubKeys = bannedSignerPubKeys;
|
||||
}
|
||||
|
||||
|
||||
@ -156,7 +162,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
byte[] ownerPubKeyBytes,
|
||||
@Nullable Map<String, String> extraDataMap,
|
||||
@Nullable List<String> mediators,
|
||||
@Nullable List<String> refundAgents) {
|
||||
@Nullable List<String> refundAgents,
|
||||
@Nullable List<String> bannedSignerPubKeys) {
|
||||
this(bannedOfferIds,
|
||||
bannedNodeAddress,
|
||||
bannedPaymentAccounts,
|
||||
@ -171,7 +178,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
disableDaoBelowVersion,
|
||||
disableTradeBelowVersion,
|
||||
mediators,
|
||||
refundAgents);
|
||||
refundAgents,
|
||||
bannedSignerPubKeys);
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.ownerPubKeyBytes = ownerPubKeyBytes;
|
||||
this.extraDataMap = ExtraDataMapValidator.getValidatedExtraDataMap(extraDataMap);
|
||||
@ -206,6 +214,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
Optional.ofNullable(extraDataMap).ifPresent(builder::putAllExtraData);
|
||||
Optional.ofNullable(mediators).ifPresent(builder::addAllMediators);
|
||||
Optional.ofNullable(refundAgents).ifPresent(builder::addAllRefundAgents);
|
||||
Optional.ofNullable(bannedSignerPubKeys).ifPresent(builder::addAllBannedSignerPubKeys);
|
||||
|
||||
return protobuf.StoragePayload.newBuilder().setFilter(builder).build();
|
||||
}
|
||||
@ -230,7 +239,9 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
proto.getOwnerPubKeyBytes().toByteArray(),
|
||||
CollectionUtils.isEmpty(proto.getExtraDataMap()) ? null : proto.getExtraDataMap(),
|
||||
CollectionUtils.isEmpty(proto.getMediatorsList()) ? null : new ArrayList<>(proto.getMediatorsList()),
|
||||
CollectionUtils.isEmpty(proto.getRefundAgentsList()) ? null : new ArrayList<>(proto.getRefundAgentsList()));
|
||||
CollectionUtils.isEmpty(proto.getRefundAgentsList()) ? null : new ArrayList<>(proto.getRefundAgentsList()),
|
||||
CollectionUtils.isEmpty(proto.getBannedSignerPubKeysList()) ?
|
||||
null : new ArrayList<>(proto.getBannedSignerPubKeysList()));
|
||||
}
|
||||
|
||||
|
||||
@ -269,6 +280,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
",\n disableTradeBelowVersion='" + disableTradeBelowVersion + '\'' +
|
||||
",\n mediators=" + mediators +
|
||||
",\n refundAgents=" + refundAgents +
|
||||
",\n bannedSignerPubKeys=" + bannedSignerPubKeys +
|
||||
"\n}";
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package bisq.core.filter;
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.btc.nodes.BtcNodes;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
@ -332,6 +333,7 @@ public class FilterManager {
|
||||
|
||||
Optional.ofNullable(filter.getBannedCurrencies()).ifPresent(builder::addAllBannedCurrencies);
|
||||
Optional.ofNullable(filter.getBannedPaymentMethods()).ifPresent(builder::addAllBannedPaymentMethods);
|
||||
Optional.ofNullable(filter.getBannedSignerPubKeys()).ifPresent(builder::addAllBannedSignerPubKeys);
|
||||
|
||||
return Utils.HEX.encode(builder.build().toByteArray());
|
||||
}
|
||||
@ -417,4 +419,12 @@ public class FilterManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isSignerPubKeyBanned(String signerPubKeyAsHex) {
|
||||
return getFilter() != null &&
|
||||
getFilter().getBannedSignerPubKeys() != null &&
|
||||
getFilter().getBannedSignerPubKeys().stream()
|
||||
.anyMatch(e -> e.equals(signerPubKeyAsHex));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -343,6 +343,7 @@ offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign
|
||||
offerbook.timeSinceSigning.info.peer=signed by a peer, waiting for limits to be lifted
|
||||
offerbook.timeSinceSigning.info.peerLimitLifted=signed by a peer and limits were lifted
|
||||
offerbook.timeSinceSigning.info.signer=signed by peer and can sign peer accounts (limits lifted)
|
||||
offerbook.timeSinceSigning.info.banned=account was banned
|
||||
offerbook.timeSinceSigning.daysSinceSigning={0} days
|
||||
offerbook.timeSinceSigning.daysSinceSigning.long={0} since signing
|
||||
|
||||
@ -2398,6 +2399,7 @@ filterWindow.onions=Filtered onion addresses (comma sep.)
|
||||
filterWindow.accounts=Filtered trading account data:\nFormat: comma sep. list of [payment method id | data field | value]
|
||||
filterWindow.bannedCurrencies=Filtered currency codes (comma sep.)
|
||||
filterWindow.bannedPaymentMethods=Filtered payment method IDs (comma sep.)
|
||||
filterWindow.bannedSignerPubKeys=Filtered signer pubkeys (comma sep. hex of pubkeys)
|
||||
filterWindow.arbitrators=Filtered arbitrators (comma sep. onion addresses)
|
||||
filterWindow.mediators=Filtered mediators (comma sep. onion addresses)
|
||||
filterWindow.refundAgents=Filtered refund agents (comma sep. onion addresses)
|
||||
@ -2477,6 +2479,7 @@ tradeDetailsWindow.disputedPayoutTxId=Disputed payout transaction ID:
|
||||
tradeDetailsWindow.tradeDate=Trade date
|
||||
tradeDetailsWindow.txFee=Mining fee
|
||||
tradeDetailsWindow.tradingPeersOnion=Trading peers onion address
|
||||
tradeDetailsWindow.tradingPeersPubKeyHash=Trading peers pubkey hash
|
||||
tradeDetailsWindow.tradeState=Trade state
|
||||
tradeDetailsWindow.agentAddresses=Arbitrator/Mediator
|
||||
|
||||
|
@ -19,6 +19,7 @@ package bisq.core.account.sign;
|
||||
|
||||
|
||||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
@ -79,7 +80,11 @@ public class SignedWitnessServiceTest {
|
||||
private long SIGN_AGE_3 = SignedWitnessService.SIGNER_AGE_DAYS + 3;
|
||||
private KeyRing keyRing;
|
||||
private P2PService p2pService;
|
||||
|
||||
private FilterManager filterManager;
|
||||
private ECKey arbitrator1Key;
|
||||
KeyPair peer1KeyPair;
|
||||
KeyPair peer2KeyPair;
|
||||
KeyPair peer3KeyPair;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
@ -88,7 +93,8 @@ public class SignedWitnessServiceTest {
|
||||
when(arbitratorManager.isPublicKeyInList(any())).thenReturn(true);
|
||||
keyRing = mock(KeyRing.class);
|
||||
p2pService = mock(P2PService.class);
|
||||
signedWitnessService = new SignedWitnessService(keyRing, p2pService, arbitratorManager, null, appendOnlyDataStoreService, null);
|
||||
filterManager = mock(FilterManager.class);
|
||||
signedWitnessService = new SignedWitnessService(keyRing, p2pService, arbitratorManager, null, appendOnlyDataStoreService, null, filterManager);
|
||||
account1DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{1});
|
||||
account2DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{2});
|
||||
account3DataHash = org.bitcoinj.core.Utils.sha256hash160(new byte[]{3});
|
||||
@ -98,10 +104,10 @@ public class SignedWitnessServiceTest {
|
||||
aew1 = new AccountAgeWitness(account1DataHash, account1CreationTime);
|
||||
aew2 = new AccountAgeWitness(account2DataHash, account2CreationTime);
|
||||
aew3 = new AccountAgeWitness(account3DataHash, account3CreationTime);
|
||||
ECKey arbitrator1Key = new ECKey();
|
||||
KeyPair peer1KeyPair = Sig.generateKeyPair();
|
||||
KeyPair peer2KeyPair = Sig.generateKeyPair();
|
||||
KeyPair peer3KeyPair = Sig.generateKeyPair();
|
||||
arbitrator1Key = new ECKey();
|
||||
peer1KeyPair = Sig.generateKeyPair();
|
||||
peer2KeyPair = Sig.generateKeyPair();
|
||||
peer3KeyPair = Sig.generateKeyPair();
|
||||
signature1 = arbitrator1Key.signMessage(Utilities.encodeToHex(account1DataHash)).getBytes(Charsets.UTF_8);
|
||||
signature2 = Sig.sign(peer1KeyPair.getPrivate(), Utilities.encodeToHex(account2DataHash).getBytes(Charsets.UTF_8));
|
||||
signature3 = Sig.sign(peer2KeyPair.getPrivate(), Utilities.encodeToHex(account3DataHash).getBytes(Charsets.UTF_8));
|
||||
@ -368,5 +374,134 @@ public class SignedWitnessServiceTest {
|
||||
|
||||
verify(p2pService, times(1)).addPersistableNetworkPayload(any(PersistableNetworkPayload.class), anyBoolean());
|
||||
}
|
||||
|
||||
/* Signed witness tree
|
||||
Each edge in the graph represents one signature
|
||||
|
||||
Arbitrator
|
||||
|
|
||||
sw1
|
||||
|
|
||||
sw2
|
||||
|
|
||||
sw3
|
||||
*/
|
||||
@Test
|
||||
public void testBanFilterSingleTree() {
|
||||
SignedWitness sw1 = new SignedWitness(ARBITRATOR, account1DataHash, signature1, signer1PubKey, witnessOwner1PubKey, date1, tradeAmount1);
|
||||
SignedWitness sw2 = new SignedWitness(TRADE, account2DataHash, signature2, signer2PubKey, witnessOwner2PubKey, date2, tradeAmount2);
|
||||
SignedWitness sw3 = new SignedWitness(TRADE, account3DataHash, signature3, signer3PubKey, witnessOwner3PubKey, date3, tradeAmount3);
|
||||
|
||||
signedWitnessService.addToMap(sw1);
|
||||
signedWitnessService.addToMap(sw2);
|
||||
signedWitnessService.addToMap(sw3);
|
||||
|
||||
// Second account is banned, first account is still a signer but the other two are no longer signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(true);
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
|
||||
// First account is banned, no accounts in the tree below it are signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(false);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
}
|
||||
|
||||
/* Signed witness trees
|
||||
Each edge in the graph represents one signature
|
||||
|
||||
Arbitrator
|
||||
| |
|
||||
sw1 sw2
|
||||
|
|
||||
sw3
|
||||
*/
|
||||
@Test
|
||||
public void testBanFilterTwoTrees() {
|
||||
// Signer 2 is signed by arbitrator
|
||||
signer2PubKey = arbitrator1Key.getPubKey();
|
||||
signature2 = arbitrator1Key.signMessage(Utilities.encodeToHex(account2DataHash)).getBytes(Charsets.UTF_8);
|
||||
|
||||
SignedWitness sw1 = new SignedWitness(ARBITRATOR, account1DataHash, signature1, signer1PubKey, witnessOwner1PubKey, date1, tradeAmount1);
|
||||
SignedWitness sw2 = new SignedWitness(ARBITRATOR, account2DataHash, signature2, signer2PubKey, witnessOwner2PubKey, date2, tradeAmount2);
|
||||
SignedWitness sw3 = new SignedWitness(TRADE, account3DataHash, signature3, signer3PubKey, witnessOwner3PubKey, date3, tradeAmount3);
|
||||
|
||||
signedWitnessService.addToMap(sw1);
|
||||
signedWitnessService.addToMap(sw2);
|
||||
signedWitnessService.addToMap(sw3);
|
||||
|
||||
// Only second account is banned, first account is still a signer but the other two are no longer signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(true);
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
|
||||
// Only first account is banned, account2 and account3 are still signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(false);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
}
|
||||
|
||||
/* Signed witness tree
|
||||
Each edge in the graph represents one signature
|
||||
|
||||
Arbitrator
|
||||
| |
|
||||
sw1 sw2
|
||||
\ /
|
||||
sw3
|
||||
*/
|
||||
@Test
|
||||
public void testBanFilterJoinedTrees() throws Exception {
|
||||
// Signer 2 is signed by arbitrator
|
||||
signer2PubKey = arbitrator1Key.getPubKey();
|
||||
signature2 = arbitrator1Key.signMessage(Utilities.encodeToHex(account2DataHash)).getBytes(Charsets.UTF_8);
|
||||
|
||||
// Peer1 owns both account1 and account2
|
||||
// witnessOwner2PubKey = witnessOwner1PubKey;
|
||||
// peer2KeyPair = peer1KeyPair;
|
||||
// signature3 = Sig.sign(peer2KeyPair.getPrivate(), Utilities.encodeToHex(account3DataHash).getBytes(Charsets.UTF_8));
|
||||
|
||||
// sw1 also signs sw3 (not supported yet but a possible addition for a more robust system)
|
||||
var signature3p = Sig.sign(peer1KeyPair.getPrivate(), Utilities.encodeToHex(account3DataHash).getBytes(Charsets.UTF_8));
|
||||
var signer3pPubKey = witnessOwner1PubKey;
|
||||
var date3p = date3;
|
||||
var tradeAmount3p = tradeAmount3;
|
||||
|
||||
SignedWitness sw1 = new SignedWitness(ARBITRATOR, account1DataHash, signature1, signer1PubKey, witnessOwner1PubKey, date1, tradeAmount1);
|
||||
SignedWitness sw2 = new SignedWitness(ARBITRATOR, account2DataHash, signature2, signer2PubKey, witnessOwner2PubKey, date2, tradeAmount2);
|
||||
SignedWitness sw3 = new SignedWitness(TRADE, account3DataHash, signature3, signer3PubKey, witnessOwner3PubKey, date3, tradeAmount3);
|
||||
SignedWitness sw3p = new SignedWitness(TRADE, account3DataHash, signature3p, signer3pPubKey, witnessOwner3PubKey, date3p, tradeAmount3p);
|
||||
|
||||
signedWitnessService.addToMap(sw1);
|
||||
signedWitnessService.addToMap(sw2);
|
||||
signedWitnessService.addToMap(sw3);
|
||||
signedWitnessService.addToMap(sw3p);
|
||||
|
||||
// First account is banned, the other two are still signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
|
||||
// Second account is banned, the other two are still signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(false);
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(true);
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
|
||||
// First and second account is banned, the third is no longer a signer
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(true);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,53 +17,92 @@
|
||||
|
||||
package bisq.core.account.witness;
|
||||
|
||||
import bisq.core.account.sign.SignedWitness;
|
||||
import bisq.core.account.sign.SignedWitnessService;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.locale.CountryUtil;
|
||||
import bisq.core.offer.OfferPayload;
|
||||
import bisq.core.payment.ChargeBackRisk;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.payment.payload.SepaAccountPayload;
|
||||
import bisq.core.support.SupportType;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
import bisq.core.support.dispute.DisputeResult;
|
||||
import bisq.core.support.dispute.arbitration.TraderDataItem;
|
||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||
import bisq.core.trade.Contract;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
import bisq.network.p2p.storage.persistence.AppendOnlyDataStoreService;
|
||||
|
||||
import bisq.common.crypto.CryptoException;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.crypto.KeyStorage;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
// Restricted default Java security policy on Travis does not allow long keys, so test fails.
|
||||
// Using Utilities.removeCryptographyRestrictions(); did not work.
|
||||
@Ignore
|
||||
//@Ignore
|
||||
public class AccountAgeWitnessServiceTest {
|
||||
private PublicKey publicKey;
|
||||
private KeyPair keypair;
|
||||
private SignedWitnessService signedWitnessService;
|
||||
private AccountAgeWitnessService service;
|
||||
private ChargeBackRisk chargeBackRisk;
|
||||
private FilterManager filterManager;
|
||||
|
||||
@Before
|
||||
public void setup() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, CryptoException {
|
||||
SignedWitnessService signedWitnessService = mock(SignedWitnessService.class);
|
||||
ChargeBackRisk chargeBackRisk = mock(ChargeBackRisk.class);
|
||||
service = new AccountAgeWitnessService(null, null, null, signedWitnessService, chargeBackRisk, null, null, null);
|
||||
public void setup() {
|
||||
chargeBackRisk = mock(ChargeBackRisk.class);
|
||||
AppendOnlyDataStoreService dataStoreService = mock(AppendOnlyDataStoreService.class);
|
||||
KeyRing keyRing = mock(KeyRing.class);
|
||||
P2PService p2pService = mock(P2PService.class);
|
||||
ArbitratorManager arbitratorManager = mock(ArbitratorManager.class);
|
||||
when(arbitratorManager.isPublicKeyInList(any())).thenReturn(true);
|
||||
AppendOnlyDataStoreService appendOnlyDataStoreService = mock(AppendOnlyDataStoreService.class);
|
||||
filterManager = mock(FilterManager.class);
|
||||
signedWitnessService = new SignedWitnessService(keyRing, p2pService, arbitratorManager, null, appendOnlyDataStoreService, null, filterManager);
|
||||
service = new AccountAgeWitnessService(null, null, null, signedWitnessService, chargeBackRisk, null, dataStoreService, filterManager);
|
||||
keypair = Sig.generateKeyPair();
|
||||
publicKey = keypair.getPublic();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws IOException {
|
||||
public void tearDown() {
|
||||
// Do teardown stuff
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testIsTradeDateAfterReleaseDate() throws CryptoException {
|
||||
Date ageWitnessReleaseDate = new GregorianCalendar(2017, 9, 23).getTime();
|
||||
@ -84,6 +123,7 @@ public class AccountAgeWitnessServiceTest {
|
||||
}));
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testVerifySignatureOfNonce() throws CryptoException {
|
||||
byte[] nonce = new byte[]{0x01};
|
||||
@ -97,4 +137,113 @@ public class AccountAgeWitnessServiceTest {
|
||||
assertFalse(service.verifySignature(publicKey, new byte[]{0x02}, new byte[]{0x04}, errorMessage -> {
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArbitratorSignWitness() throws IOException {
|
||||
// Setup temp storage dir
|
||||
File dir1 = File.createTempFile("temp_tests1", "");
|
||||
dir1.delete();
|
||||
dir1.mkdir();
|
||||
File dir2 = File.createTempFile("temp_tests1", "");
|
||||
dir2.delete();
|
||||
dir2.mkdir();
|
||||
|
||||
KeyRing buyerKeyRing = new KeyRing(new KeyStorage(dir1));
|
||||
KeyRing sellerKeyRing = new KeyRing(new KeyStorage(dir2));
|
||||
|
||||
// Setup dispute for arbitrator to sign both sides
|
||||
List<Dispute> disputes = new ArrayList<>();
|
||||
PubKeyRing buyerPubKeyRing = buyerKeyRing.getPubKeyRing();
|
||||
PubKeyRing sellerPubKeyRing = sellerKeyRing.getPubKeyRing();
|
||||
PaymentAccountPayload buyerPaymentAccountPayload = new SepaAccountPayload(PaymentMethod.SEPA_ID, "1", CountryUtil.getAllSepaCountries());
|
||||
PaymentAccountPayload sellerPaymentAccountPayload = new SepaAccountPayload(PaymentMethod.SEPA_ID, "2", CountryUtil.getAllSepaCountries());
|
||||
AccountAgeWitness buyerAccountAgeWitness = service.getNewWitness(buyerPaymentAccountPayload, buyerPubKeyRing);
|
||||
service.addToMap(buyerAccountAgeWitness);
|
||||
AccountAgeWitness sellerAccountAgeWitness = service.getNewWitness(sellerPaymentAccountPayload, sellerPubKeyRing);
|
||||
service.addToMap(sellerAccountAgeWitness);
|
||||
long now = new Date().getTime() + 1000;
|
||||
Contract contract = mock(Contract.class);
|
||||
disputes.add(new Dispute(
|
||||
"trade1",
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
buyerPubKeyRing,
|
||||
now - 1,
|
||||
contract,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"contractAsJson",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
SupportType.ARBITRATION));
|
||||
disputes.get(0).getIsClosedProperty().set(true);
|
||||
disputes.get(0).getDisputeResultProperty().set(new DisputeResult(
|
||||
"trade1",
|
||||
1,
|
||||
DisputeResult.Winner.BUYER,
|
||||
DisputeResult.Reason.OTHER.ordinal(),
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
"summary",
|
||||
null,
|
||||
null,
|
||||
100000,
|
||||
0,
|
||||
null,
|
||||
now - 1,
|
||||
false));
|
||||
|
||||
// Filtermanager says nothing is filtered
|
||||
when(filterManager.isNodeAddressBanned(any())).thenReturn(false);
|
||||
when(filterManager.isCurrencyBanned(any())).thenReturn(false);
|
||||
when(filterManager.isPaymentMethodBanned(any())).thenReturn(false);
|
||||
when(filterManager.isPeersPaymentAccountDataAreBanned(any(), any())).thenReturn(false);
|
||||
when(filterManager.isSignerPubKeyBanned(any())).thenReturn(false);
|
||||
|
||||
when(chargeBackRisk.hasChargebackRisk(any(), any())).thenReturn(true);
|
||||
|
||||
when(contract.getPaymentMethodId()).thenReturn(PaymentMethod.SEPA_ID);
|
||||
when(contract.getTradeAmount()).thenReturn(Coin.parseCoin("0.01"));
|
||||
when(contract.getBuyerPubKeyRing()).thenReturn(buyerPubKeyRing);
|
||||
when(contract.getSellerPubKeyRing()).thenReturn(sellerPubKeyRing);
|
||||
when(contract.getBuyerPaymentAccountPayload()).thenReturn(buyerPaymentAccountPayload);
|
||||
when(contract.getSellerPaymentAccountPayload()).thenReturn(sellerPaymentAccountPayload);
|
||||
when(contract.getOfferPayload()).thenReturn(mock(OfferPayload.class));
|
||||
List<TraderDataItem> items = service.getTraderPaymentAccounts(now, PaymentMethod.SEPA, disputes);
|
||||
assertEquals(items.size(), 2);
|
||||
|
||||
// Setup a mocked arbitrator key
|
||||
ECKey arbitratorKey = mock(ECKey.class);
|
||||
when(arbitratorKey.signMessage(any())).thenReturn("1");
|
||||
when(arbitratorKey.signMessage(any())).thenReturn("2");
|
||||
when(arbitratorKey.getPubKey()).thenReturn("1".getBytes());
|
||||
|
||||
// Arbitrator signs both trader accounts
|
||||
items.forEach(item -> service.arbitratorSignAccountAgeWitness(
|
||||
item.getTradeAmount(),
|
||||
item.getAccountAgeWitness(),
|
||||
arbitratorKey,
|
||||
item.getPeersPubKey()));
|
||||
|
||||
// Check that both accountAgeWitnesses are signed
|
||||
SignedWitness foundBuyerSignedWitness = signedWitnessService.getSignedWitnessSetByOwnerPubKey(
|
||||
buyerPubKeyRing.getSignaturePubKeyBytes()).stream()
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertEquals(Utilities.bytesAsHexString(foundBuyerSignedWitness.getAccountAgeWitnessHash()),
|
||||
Utilities.bytesAsHexString(buyerAccountAgeWitness.getHash()));
|
||||
SignedWitness foundSellerSignedWitness = signedWitnessService.getSignedWitnessSetByOwnerPubKey(
|
||||
sellerPubKeyRing.getSignaturePubKeyBytes()).stream()
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertEquals(Utilities.bytesAsHexString(foundSellerSignedWitness.getAccountAgeWitnessHash()),
|
||||
Utilities.bytesAsHexString(sellerAccountAgeWitness.getHash()));
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ public class UserPayloadModelVOTest {
|
||||
new byte[]{10, 0, 0},
|
||||
null,
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList()));
|
||||
vo.setRegisteredArbitrator(ArbitratorTest.getArbitratorMock());
|
||||
vo.setRegisteredMediator(MediatorTest.getMediatorMock());
|
||||
|
@ -39,9 +39,11 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
@ -58,6 +60,7 @@ import static bisq.desktop.util.FormBuilder.addTopLabelInputTextField;
|
||||
public class FilterWindow extends Overlay<FilterWindow> {
|
||||
private final FilterManager filterManager;
|
||||
private final boolean useDevPrivilegeKeys;
|
||||
private ScrollPane scrollPane;
|
||||
|
||||
@Inject
|
||||
public FilterWindow(FilterManager filterManager,
|
||||
@ -67,12 +70,26 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
type = Type.Attention;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region getRootContainer() {
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (headLine == null)
|
||||
headLine = Res.get("filterWindow.headline");
|
||||
|
||||
width = 968;
|
||||
|
||||
createGridPane();
|
||||
|
||||
scrollPane = new ScrollPane();
|
||||
scrollPane.setContent(gridPane);
|
||||
scrollPane.setFitToWidth(true);
|
||||
scrollPane.setFitToHeight(true);
|
||||
scrollPane.setMaxHeight(1000);
|
||||
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
|
||||
addHeadLine();
|
||||
addContent();
|
||||
applyStyles();
|
||||
@ -108,6 +125,8 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
InputTextField bannedCurrenciesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.bannedCurrencies"));
|
||||
InputTextField bannedPaymentMethodsInputTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.bannedPaymentMethods")).second;
|
||||
bannedPaymentMethodsInputTextField.setPromptText("E.g. PERFECT_MONEY"); // Do not translate
|
||||
InputTextField bannedSignerPubKeysInputTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.bannedSignerPubKeys")).second;
|
||||
bannedSignerPubKeysInputTextField.setPromptText("E.g. 7f66117aa084e5a2c54fe17d29dd1fee2b241257"); // Do not translate
|
||||
InputTextField arbitratorsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.arbitrators"));
|
||||
InputTextField mediatorsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.mediators"));
|
||||
InputTextField refundAgentsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.refundAgents"));
|
||||
@ -126,12 +145,14 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
setupFieldFromPaymentAccountFiltersList(paymentAccountFilterInputTextField, filter.getBannedPaymentAccounts());
|
||||
setupFieldFromList(bannedCurrenciesInputTextField, filter.getBannedCurrencies());
|
||||
setupFieldFromList(bannedPaymentMethodsInputTextField, filter.getBannedPaymentMethods());
|
||||
setupFieldFromList(bannedSignerPubKeysInputTextField, filter.getBannedSignerPubKeys());
|
||||
setupFieldFromList(arbitratorsInputTextField, filter.getArbitrators());
|
||||
setupFieldFromList(mediatorsInputTextField, filter.getMediators());
|
||||
setupFieldFromList(refundAgentsInputTextField, filter.getRefundAgents());
|
||||
setupFieldFromList(seedNodesInputTextField, filter.getSeedNodes());
|
||||
setupFieldFromList(priceRelayNodesInputTextField, filter.getPriceRelayNodes());
|
||||
setupFieldFromList(btcNodesInputTextField, filter.getBtcNodes());
|
||||
|
||||
preventPublicBtcNetworkCheckBox.setSelected(filter.isPreventPublicBtcNetwork());
|
||||
disableDaoCheckBox.setSelected(filter.isDisableDao());
|
||||
disableDaoBelowVersionInputTextField.setText(filter.getDisableDaoBelowVersion());
|
||||
@ -155,7 +176,8 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
disableDaoBelowVersionInputTextField.getText(),
|
||||
disableTradeBelowVersionInputTextField.getText(),
|
||||
readAsList(mediatorsInputTextField),
|
||||
readAsList(refundAgentsInputTextField)
|
||||
readAsList(refundAgentsInputTextField),
|
||||
readAsList(bannedSignerPubKeysInputTextField)
|
||||
),
|
||||
keyInputTextField.getText())
|
||||
)
|
||||
|
@ -39,6 +39,7 @@ import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.bitcoinj.core.Utils;
|
||||
|
||||
@ -232,6 +233,12 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
|
||||
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.tradingPeersOnion"),
|
||||
trade.getTradingPeerNodeAddress().getFullAddress());
|
||||
|
||||
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex,
|
||||
Res.get("tradeDetailsWindow.tradingPeersPubKeyHash"),
|
||||
trade.getContract() != null ? Utils.HEX.encode(trade.getContract().getPeersPubKeyRing(
|
||||
tradeManager.getKeyRing().getPubKeyRing()).getSignaturePubKeyBytes()) :
|
||||
Res.get("shared.na"));
|
||||
|
||||
if (contract != null) {
|
||||
if (buyerPaymentAccountPayload != null) {
|
||||
String paymentDetails = buyerPaymentAccountPayload.getPaymentDetails();
|
||||
|
@ -227,8 +227,10 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
||||
onBitcoinPeersToggleSelected(false);
|
||||
|
||||
bitcoinPeersToggleGroupListener = (observable, oldValue, newValue) -> {
|
||||
selectedBitcoinNodesOption = (BtcNodes.BitcoinNodesOption) newValue.getUserData();
|
||||
onBitcoinPeersToggleSelected(true);
|
||||
if (newValue != null) {
|
||||
selectedBitcoinNodesOption = (BtcNodes.BitcoinNodesOption) newValue.getUserData();
|
||||
onBitcoinPeersToggleSelected(true);
|
||||
}
|
||||
};
|
||||
|
||||
btcNodesInputTextField.setPromptText(Res.get("settings.net.ips"));
|
||||
|
@ -628,6 +628,7 @@ message Filter {
|
||||
string disable_trade_below_version = 16;
|
||||
repeated string mediators = 17;
|
||||
repeated string refundAgents = 18;
|
||||
repeated string bannedSignerPubKeys = 19;
|
||||
}
|
||||
|
||||
// not used anymore from v0.6 on. But leave it for receiving TradeStatistics objects from older
|
||||
|
Loading…
Reference in New Issue
Block a user