mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Merge pull request #4460 from chimp1984/refactor-filter
Refactor filter
This commit is contained in:
commit
7830dbf4e4
@ -18,12 +18,15 @@
|
||||
package bisq.common.proto;
|
||||
|
||||
import bisq.common.Proto;
|
||||
import bisq.common.util.CollectionUtils;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import com.google.protobuf.ProtocolStringList;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -95,4 +98,9 @@ public class ProtoUtil {
|
||||
public static <T> Iterable<T> collectionToProto(Collection<? extends Proto> collection, Function<? super Message, T> extra) {
|
||||
return collection.stream().map(o -> extra.apply(o.toProtoMessage())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> protocolStringListToList(ProtocolStringList protocolStringList) {
|
||||
return CollectionUtils.isEmpty(protocolStringList) ? new ArrayList<>() : new ArrayList<>(protocolStringList);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ public class SignedWitnessService {
|
||||
public boolean isFilteredWitness(AccountAgeWitness accountAgeWitness) {
|
||||
return getSignedWitnessSet(accountAgeWitness).stream()
|
||||
.map(SignedWitness::getWitnessOwnerPubKey)
|
||||
.anyMatch(ownerPubKey -> filterManager.isSignerPubKeyBanned(Utils.HEX.encode(ownerPubKey)));
|
||||
.anyMatch(ownerPubKey -> filterManager.isWitnessSignerPubKeyBanned(Utils.HEX.encode(ownerPubKey)));
|
||||
}
|
||||
|
||||
private byte[] ownerPubKey(AccountAgeWitness accountAgeWitness) {
|
||||
@ -442,7 +442,7 @@ public class SignedWitnessService {
|
||||
private boolean isValidSignerWitnessInternal(SignedWitness signedWitness,
|
||||
long childSignedWitnessDateMillis,
|
||||
Stack<P2PDataStorage.ByteArray> excludedPubKeys) {
|
||||
if (filterManager.isSignerPubKeyBanned(Utils.HEX.encode(signedWitness.getWitnessOwnerPubKey()))) {
|
||||
if (filterManager.isWitnessSignerPubKeyBanned(Utils.HEX.encode(signedWitness.getWitnessOwnerPubKey()))) {
|
||||
return false;
|
||||
}
|
||||
if (!verifySignature(signedWitness)) {
|
||||
|
@ -713,13 +713,13 @@ public class AccountAgeWitnessService {
|
||||
filterManager.isCurrencyBanned(dispute.getContract().getOfferPayload().getCurrencyCode()) ||
|
||||
filterManager.isPaymentMethodBanned(
|
||||
PaymentMethod.getPaymentMethodById(dispute.getContract().getPaymentMethodId())) ||
|
||||
filterManager.isPeersPaymentAccountDataAreBanned(dispute.getContract().getBuyerPaymentAccountPayload(),
|
||||
filterManager.arePeersPaymentAccountDataBanned(dispute.getContract().getBuyerPaymentAccountPayload(),
|
||||
new PaymentAccountFilter[1]) ||
|
||||
filterManager.isPeersPaymentAccountDataAreBanned(dispute.getContract().getSellerPaymentAccountPayload(),
|
||||
filterManager.arePeersPaymentAccountDataBanned(dispute.getContract().getSellerPaymentAccountPayload(),
|
||||
new PaymentAccountFilter[1]) ||
|
||||
filterManager.isSignerPubKeyBanned(
|
||||
filterManager.isWitnessSignerPubKeyBanned(
|
||||
Utils.HEX.encode(dispute.getContract().getBuyerPubKeyRing().getSignaturePubKeyBytes())) ||
|
||||
filterManager.isSignerPubKeyBanned(
|
||||
filterManager.isWitnessSignerPubKeyBanned(
|
||||
Utils.HEX.encode(dispute.getContract().getSellerPubKeyRing().getSignaturePubKeyBytes()));
|
||||
return !isFiltered;
|
||||
}
|
||||
|
@ -21,8 +21,10 @@ import bisq.network.p2p.storage.payload.ExpirablePayload;
|
||||
import bisq.network.p2p.storage.payload.ProtectedStoragePayload;
|
||||
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
import bisq.common.util.CollectionUtils;
|
||||
import bisq.common.util.ExtraDataMapValidator;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
@ -30,147 +32,135 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
@Value
|
||||
public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
private final List<String> bannedOfferIds;
|
||||
private final List<String> bannedNodeAddress;
|
||||
private final List<PaymentAccountFilter> bannedPaymentAccounts;
|
||||
|
||||
// Because we added those fields in v 0.5.4 and old versions do not have it we annotate it with @Nullable
|
||||
@Nullable
|
||||
private final List<String> bannedCurrencies;
|
||||
@Nullable
|
||||
private final List<String> bannedPaymentMethods;
|
||||
|
||||
// added in v0.6.0
|
||||
@Nullable
|
||||
private final List<String> arbitrators;
|
||||
@Nullable
|
||||
private final List<String> seedNodes;
|
||||
@Nullable
|
||||
private final List<String> priceRelayNodes;
|
||||
private final boolean preventPublicBtcNetwork;
|
||||
|
||||
// added in v0.6.2
|
||||
@Nullable
|
||||
private final List<String> btcNodes;
|
||||
// SignatureAsBase64 is not set initially as we use the serialized data for signing. We set it after signature is
|
||||
// created by cloning the object with a non-null sig.
|
||||
@Nullable
|
||||
private final String signatureAsBase64;
|
||||
// The pub EC key from the dev who has signed and published the filter (different to ownerPubKeyBytes)
|
||||
private final String signerPubKeyAsHex;
|
||||
|
||||
// The pub key used for the data protection in the p2p storage
|
||||
private final byte[] ownerPubKeyBytes;
|
||||
private final boolean disableDao;
|
||||
private final String disableDaoBelowVersion;
|
||||
private final String disableTradeBelowVersion;
|
||||
private final List<String> mediators;
|
||||
private final List<String> refundAgents;
|
||||
|
||||
private final List<String> bannedAccountWitnessSignerPubKeys;
|
||||
|
||||
private final List<String> btcFeeReceiverAddresses;
|
||||
|
||||
private final long creationDate;
|
||||
|
||||
private final List<String> bannedPrivilegedDevPubKeys;
|
||||
|
||||
private String signatureAsBase64;
|
||||
private byte[] ownerPubKeyBytes;
|
||||
// Should be only used in emergency case if we need to add data but do not want to break backward compatibility
|
||||
// at the P2P network storage checks. The hash of the object will be used to verify if the data is valid. Any new
|
||||
// field in a class would break that hash and therefore break the storage mechanism.
|
||||
@Nullable
|
||||
private Map<String, String> extraDataMap;
|
||||
private PublicKey ownerPubKey;
|
||||
|
||||
// added in v0.9.4
|
||||
private final boolean disableDao;
|
||||
private transient PublicKey ownerPubKey;
|
||||
|
||||
// added in v0.9.8
|
||||
@Nullable
|
||||
private final String disableDaoBelowVersion;
|
||||
@Nullable
|
||||
private final String disableTradeBelowVersion;
|
||||
|
||||
// added in v1.1.6
|
||||
@Nullable
|
||||
private final List<String> mediators;
|
||||
|
||||
// added in v1.2.0
|
||||
@Nullable
|
||||
private final List<String> refundAgents;
|
||||
|
||||
// added in v1.2.x
|
||||
@Nullable
|
||||
private final List<String> bannedSignerPubKeys;
|
||||
|
||||
// added in v1.3.2
|
||||
@Nullable
|
||||
private final List<String> btcFeeReceiverAddresses;
|
||||
|
||||
public Filter(List<String> bannedOfferIds,
|
||||
List<String> bannedNodeAddress,
|
||||
List<PaymentAccountFilter> bannedPaymentAccounts,
|
||||
@Nullable List<String> bannedCurrencies,
|
||||
@Nullable List<String> bannedPaymentMethods,
|
||||
@Nullable List<String> arbitrators,
|
||||
@Nullable List<String> seedNodes,
|
||||
@Nullable List<String> priceRelayNodes,
|
||||
boolean preventPublicBtcNetwork,
|
||||
@Nullable List<String> btcNodes,
|
||||
boolean disableDao,
|
||||
@Nullable String disableDaoBelowVersion,
|
||||
@Nullable String disableTradeBelowVersion,
|
||||
@Nullable List<String> mediators,
|
||||
@Nullable List<String> refundAgents,
|
||||
@Nullable List<String> bannedSignerPubKeys,
|
||||
@Nullable List<String> btcFeeReceiverAddresses) {
|
||||
this.bannedOfferIds = bannedOfferIds;
|
||||
this.bannedNodeAddress = bannedNodeAddress;
|
||||
this.bannedPaymentAccounts = bannedPaymentAccounts;
|
||||
this.bannedCurrencies = bannedCurrencies;
|
||||
this.bannedPaymentMethods = bannedPaymentMethods;
|
||||
this.arbitrators = arbitrators;
|
||||
this.seedNodes = seedNodes;
|
||||
this.priceRelayNodes = priceRelayNodes;
|
||||
this.preventPublicBtcNetwork = preventPublicBtcNetwork;
|
||||
this.btcNodes = btcNodes;
|
||||
this.disableDao = disableDao;
|
||||
this.disableDaoBelowVersion = disableDaoBelowVersion;
|
||||
this.disableTradeBelowVersion = disableTradeBelowVersion;
|
||||
this.mediators = mediators;
|
||||
this.refundAgents = refundAgents;
|
||||
this.bannedSignerPubKeys = bannedSignerPubKeys;
|
||||
this.btcFeeReceiverAddresses = btcFeeReceiverAddresses;
|
||||
// After we have created the signature from the filter data we clone it and apply the signature
|
||||
static Filter cloneWithSig(Filter filter, String signatureAsBase64) {
|
||||
return new Filter(filter.getBannedOfferIds(),
|
||||
filter.getBannedNodeAddress(),
|
||||
filter.getBannedPaymentAccounts(),
|
||||
filter.getBannedCurrencies(),
|
||||
filter.getBannedPaymentMethods(),
|
||||
filter.getArbitrators(),
|
||||
filter.getSeedNodes(),
|
||||
filter.getPriceRelayNodes(),
|
||||
filter.isPreventPublicBtcNetwork(),
|
||||
filter.getBtcNodes(),
|
||||
filter.isDisableDao(),
|
||||
filter.getDisableDaoBelowVersion(),
|
||||
filter.getDisableTradeBelowVersion(),
|
||||
filter.getMediators(),
|
||||
filter.getRefundAgents(),
|
||||
filter.getBannedAccountWitnessSignerPubKeys(),
|
||||
filter.getBtcFeeReceiverAddresses(),
|
||||
filter.getOwnerPubKeyBytes(),
|
||||
filter.getCreationDate(),
|
||||
filter.getExtraDataMap(),
|
||||
signatureAsBase64,
|
||||
filter.getSignerPubKeyAsHex(),
|
||||
filter.getBannedPrivilegedDevPubKeys());
|
||||
}
|
||||
|
||||
// Used for signature verification as we created the sig without the signatureAsBase64 field we set it to null again
|
||||
static Filter cloneWithoutSig(Filter filter) {
|
||||
return new Filter(filter.getBannedOfferIds(),
|
||||
filter.getBannedNodeAddress(),
|
||||
filter.getBannedPaymentAccounts(),
|
||||
filter.getBannedCurrencies(),
|
||||
filter.getBannedPaymentMethods(),
|
||||
filter.getArbitrators(),
|
||||
filter.getSeedNodes(),
|
||||
filter.getPriceRelayNodes(),
|
||||
filter.isPreventPublicBtcNetwork(),
|
||||
filter.getBtcNodes(),
|
||||
filter.isDisableDao(),
|
||||
filter.getDisableDaoBelowVersion(),
|
||||
filter.getDisableTradeBelowVersion(),
|
||||
filter.getMediators(),
|
||||
filter.getRefundAgents(),
|
||||
filter.getBannedAccountWitnessSignerPubKeys(),
|
||||
filter.getBtcFeeReceiverAddresses(),
|
||||
filter.getOwnerPubKeyBytes(),
|
||||
filter.getCreationDate(),
|
||||
filter.getExtraDataMap(),
|
||||
null,
|
||||
filter.getSignerPubKeyAsHex(),
|
||||
filter.getBannedPrivilegedDevPubKeys());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@VisibleForTesting
|
||||
public Filter(List<String> bannedOfferIds,
|
||||
List<String> bannedNodeAddress,
|
||||
List<PaymentAccountFilter> bannedPaymentAccounts,
|
||||
@Nullable List<String> bannedCurrencies,
|
||||
@Nullable List<String> bannedPaymentMethods,
|
||||
@Nullable List<String> arbitrators,
|
||||
@Nullable List<String> seedNodes,
|
||||
@Nullable List<String> priceRelayNodes,
|
||||
List<String> bannedCurrencies,
|
||||
List<String> bannedPaymentMethods,
|
||||
List<String> arbitrators,
|
||||
List<String> seedNodes,
|
||||
List<String> priceRelayNodes,
|
||||
boolean preventPublicBtcNetwork,
|
||||
@Nullable List<String> btcNodes,
|
||||
List<String> btcNodes,
|
||||
boolean disableDao,
|
||||
@Nullable String disableDaoBelowVersion,
|
||||
@Nullable String disableTradeBelowVersion,
|
||||
String signatureAsBase64,
|
||||
byte[] ownerPubKeyBytes,
|
||||
@Nullable Map<String, String> extraDataMap,
|
||||
@Nullable List<String> mediators,
|
||||
@Nullable List<String> refundAgents,
|
||||
@Nullable List<String> bannedSignerPubKeys,
|
||||
@Nullable List<String> btcFeeReceiverAddresses) {
|
||||
String disableDaoBelowVersion,
|
||||
String disableTradeBelowVersion,
|
||||
List<String> mediators,
|
||||
List<String> refundAgents,
|
||||
List<String> bannedAccountWitnessSignerPubKeys,
|
||||
List<String> btcFeeReceiverAddresses,
|
||||
PublicKey ownerPubKey,
|
||||
String signerPubKeyAsHex,
|
||||
List<String> bannedPrivilegedDevPubKeys) {
|
||||
this(bannedOfferIds,
|
||||
bannedNodeAddress,
|
||||
bannedPaymentAccounts,
|
||||
@ -186,73 +176,141 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
disableTradeBelowVersion,
|
||||
mediators,
|
||||
refundAgents,
|
||||
bannedSignerPubKeys,
|
||||
btcFeeReceiverAddresses);
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.ownerPubKeyBytes = ownerPubKeyBytes;
|
||||
this.extraDataMap = ExtraDataMapValidator.getValidatedExtraDataMap(extraDataMap);
|
||||
bannedAccountWitnessSignerPubKeys,
|
||||
btcFeeReceiverAddresses,
|
||||
Sig.getPublicKeyBytes(ownerPubKey),
|
||||
System.currentTimeMillis(),
|
||||
null,
|
||||
null,
|
||||
signerPubKeyAsHex,
|
||||
bannedPrivilegedDevPubKeys);
|
||||
}
|
||||
|
||||
ownerPubKey = Sig.getPublicKeyFromBytes(ownerPubKeyBytes);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@VisibleForTesting
|
||||
public Filter(List<String> bannedOfferIds,
|
||||
List<String> bannedNodeAddress,
|
||||
List<PaymentAccountFilter> bannedPaymentAccounts,
|
||||
List<String> bannedCurrencies,
|
||||
List<String> bannedPaymentMethods,
|
||||
List<String> arbitrators,
|
||||
List<String> seedNodes,
|
||||
List<String> priceRelayNodes,
|
||||
boolean preventPublicBtcNetwork,
|
||||
List<String> btcNodes,
|
||||
boolean disableDao,
|
||||
String disableDaoBelowVersion,
|
||||
String disableTradeBelowVersion,
|
||||
List<String> mediators,
|
||||
List<String> refundAgents,
|
||||
List<String> bannedAccountWitnessSignerPubKeys,
|
||||
List<String> btcFeeReceiverAddresses,
|
||||
byte[] ownerPubKeyBytes,
|
||||
long creationDate,
|
||||
@Nullable Map<String, String> extraDataMap,
|
||||
@Nullable String signatureAsBase64,
|
||||
String signerPubKeyAsHex,
|
||||
List<String> bannedPrivilegedDevPubKeys) {
|
||||
this.bannedOfferIds = bannedOfferIds;
|
||||
this.bannedNodeAddress = bannedNodeAddress;
|
||||
this.bannedPaymentAccounts = bannedPaymentAccounts;
|
||||
this.bannedCurrencies = bannedCurrencies;
|
||||
this.bannedPaymentMethods = bannedPaymentMethods;
|
||||
this.arbitrators = arbitrators;
|
||||
this.seedNodes = seedNodes;
|
||||
this.priceRelayNodes = priceRelayNodes;
|
||||
this.preventPublicBtcNetwork = preventPublicBtcNetwork;
|
||||
this.btcNodes = btcNodes;
|
||||
this.disableDao = disableDao;
|
||||
this.disableDaoBelowVersion = disableDaoBelowVersion;
|
||||
this.disableTradeBelowVersion = disableTradeBelowVersion;
|
||||
this.mediators = mediators;
|
||||
this.refundAgents = refundAgents;
|
||||
this.bannedAccountWitnessSignerPubKeys = bannedAccountWitnessSignerPubKeys;
|
||||
this.btcFeeReceiverAddresses = btcFeeReceiverAddresses;
|
||||
this.ownerPubKeyBytes = ownerPubKeyBytes;
|
||||
this.creationDate = creationDate;
|
||||
this.extraDataMap = ExtraDataMapValidator.getValidatedExtraDataMap(extraDataMap);
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.signerPubKeyAsHex = signerPubKeyAsHex;
|
||||
this.bannedPrivilegedDevPubKeys = bannedPrivilegedDevPubKeys;
|
||||
|
||||
// ownerPubKeyBytes can be null when called from tests
|
||||
if (ownerPubKeyBytes != null) {
|
||||
ownerPubKey = Sig.getPublicKeyFromBytes(ownerPubKeyBytes);
|
||||
} else {
|
||||
ownerPubKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public protobuf.StoragePayload toProtoMessage() {
|
||||
checkNotNull(signatureAsBase64, "signatureAsBase64 must not be null");
|
||||
checkNotNull(ownerPubKeyBytes, "ownerPubKeyBytes must not be null");
|
||||
List<protobuf.PaymentAccountFilter> paymentAccountFilterList = bannedPaymentAccounts.stream()
|
||||
.map(PaymentAccountFilter::toProtoMessage)
|
||||
.collect(Collectors.toList());
|
||||
final protobuf.Filter.Builder builder = protobuf.Filter.newBuilder()
|
||||
.addAllBannedOfferIds(bannedOfferIds)
|
||||
|
||||
protobuf.Filter.Builder builder = protobuf.Filter.newBuilder().addAllBannedOfferIds(bannedOfferIds)
|
||||
.addAllBannedNodeAddress(bannedNodeAddress)
|
||||
.addAllBannedPaymentAccounts(paymentAccountFilterList)
|
||||
.setSignatureAsBase64(signatureAsBase64)
|
||||
.setOwnerPubKeyBytes(ByteString.copyFrom(ownerPubKeyBytes))
|
||||
.addAllBannedCurrencies(bannedCurrencies)
|
||||
.addAllBannedPaymentMethods(bannedPaymentMethods)
|
||||
.addAllArbitrators(arbitrators)
|
||||
.addAllSeedNodes(seedNodes)
|
||||
.addAllPriceRelayNodes(priceRelayNodes)
|
||||
.setPreventPublicBtcNetwork(preventPublicBtcNetwork)
|
||||
.setDisableDao(disableDao);
|
||||
.addAllBtcNodes(btcNodes)
|
||||
.setDisableDao(disableDao)
|
||||
.setDisableDaoBelowVersion(disableDaoBelowVersion)
|
||||
.setDisableTradeBelowVersion(disableTradeBelowVersion)
|
||||
.addAllMediators(mediators)
|
||||
.addAllRefundAgents(refundAgents)
|
||||
.addAllBannedSignerPubKeys(bannedAccountWitnessSignerPubKeys)
|
||||
.addAllBtcFeeReceiverAddresses(btcFeeReceiverAddresses)
|
||||
.setOwnerPubKeyBytes(ByteString.copyFrom(ownerPubKeyBytes))
|
||||
.setSignerPubKeyAsHex(signerPubKeyAsHex)
|
||||
.setCreationDate(creationDate)
|
||||
.addAllBannedPrivilegedDevPubKeys(bannedPrivilegedDevPubKeys);
|
||||
|
||||
Optional.ofNullable(bannedCurrencies).ifPresent(builder::addAllBannedCurrencies);
|
||||
Optional.ofNullable(bannedPaymentMethods).ifPresent(builder::addAllBannedPaymentMethods);
|
||||
Optional.ofNullable(arbitrators).ifPresent(builder::addAllArbitrators);
|
||||
Optional.ofNullable(seedNodes).ifPresent(builder::addAllSeedNodes);
|
||||
Optional.ofNullable(priceRelayNodes).ifPresent(builder::addAllPriceRelayNodes);
|
||||
Optional.ofNullable(btcNodes).ifPresent(builder::addAllBtcNodes);
|
||||
Optional.ofNullable(disableDaoBelowVersion).ifPresent(builder::setDisableDaoBelowVersion);
|
||||
Optional.ofNullable(disableTradeBelowVersion).ifPresent(builder::setDisableTradeBelowVersion);
|
||||
Optional.ofNullable(signatureAsBase64).ifPresent(builder::setSignatureAsBase64);
|
||||
Optional.ofNullable(extraDataMap).ifPresent(builder::putAllExtraData);
|
||||
Optional.ofNullable(mediators).ifPresent(builder::addAllMediators);
|
||||
Optional.ofNullable(refundAgents).ifPresent(builder::addAllRefundAgents);
|
||||
Optional.ofNullable(bannedSignerPubKeys).ifPresent(builder::addAllBannedSignerPubKeys);
|
||||
Optional.ofNullable(btcFeeReceiverAddresses).ifPresent(builder::addAllBtcFeeReceiverAddresses);
|
||||
|
||||
return protobuf.StoragePayload.newBuilder().setFilter(builder).build();
|
||||
}
|
||||
|
||||
public static Filter fromProto(protobuf.Filter proto) {
|
||||
return new Filter(new ArrayList<>(proto.getBannedOfferIdsList()),
|
||||
new ArrayList<>(proto.getBannedNodeAddressList()),
|
||||
proto.getBannedPaymentAccountsList().stream()
|
||||
.map(PaymentAccountFilter::fromProto)
|
||||
.collect(Collectors.toList()),
|
||||
CollectionUtils.isEmpty(proto.getBannedCurrenciesList()) ? null : new ArrayList<>(proto.getBannedCurrenciesList()),
|
||||
CollectionUtils.isEmpty(proto.getBannedPaymentMethodsList()) ? null : new ArrayList<>(proto.getBannedPaymentMethodsList()),
|
||||
CollectionUtils.isEmpty(proto.getArbitratorsList()) ? null : new ArrayList<>(proto.getArbitratorsList()),
|
||||
CollectionUtils.isEmpty(proto.getSeedNodesList()) ? null : new ArrayList<>(proto.getSeedNodesList()),
|
||||
CollectionUtils.isEmpty(proto.getPriceRelayNodesList()) ? null : new ArrayList<>(proto.getPriceRelayNodesList()),
|
||||
List<PaymentAccountFilter> bannedPaymentAccountsList = proto.getBannedPaymentAccountsList().stream()
|
||||
.map(PaymentAccountFilter::fromProto)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
return new Filter(ProtoUtil.protocolStringListToList(proto.getBannedOfferIdsList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getBannedNodeAddressList()),
|
||||
bannedPaymentAccountsList,
|
||||
ProtoUtil.protocolStringListToList(proto.getBannedCurrenciesList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getBannedPaymentMethodsList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getArbitratorsList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getSeedNodesList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getPriceRelayNodesList()),
|
||||
proto.getPreventPublicBtcNetwork(),
|
||||
CollectionUtils.isEmpty(proto.getBtcNodesList()) ? null : new ArrayList<>(proto.getBtcNodesList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getBtcNodesList()),
|
||||
proto.getDisableDao(),
|
||||
proto.getDisableDaoBelowVersion().isEmpty() ? null : proto.getDisableDaoBelowVersion(),
|
||||
proto.getDisableTradeBelowVersion().isEmpty() ? null : proto.getDisableTradeBelowVersion(),
|
||||
proto.getSignatureAsBase64(),
|
||||
proto.getDisableDaoBelowVersion(),
|
||||
proto.getDisableTradeBelowVersion(),
|
||||
ProtoUtil.protocolStringListToList(proto.getMediatorsList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getRefundAgentsList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getBannedSignerPubKeysList()),
|
||||
ProtoUtil.protocolStringListToList(proto.getBtcFeeReceiverAddressesList()),
|
||||
proto.getOwnerPubKeyBytes().toByteArray(),
|
||||
proto.getCreationDate(),
|
||||
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.getBannedSignerPubKeysList()) ?
|
||||
null : new ArrayList<>(proto.getBannedSignerPubKeysList()),
|
||||
CollectionUtils.isEmpty(proto.getBtcFeeReceiverAddressesList()) ? null :
|
||||
new ArrayList<>(proto.getBtcFeeReceiverAddressesList()));
|
||||
proto.getSignatureAsBase64(),
|
||||
proto.getSignerPubKeyAsHex(),
|
||||
ProtoUtil.protocolStringListToList(proto.getBannedPrivilegedDevPubKeysList())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -265,13 +323,6 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
return TimeUnit.DAYS.toMillis(180);
|
||||
}
|
||||
|
||||
void setSigAndPubKey(String signatureAsBase64, PublicKey ownerPubKey) {
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
this.ownerPubKey = ownerPubKey;
|
||||
|
||||
ownerPubKeyBytes = Sig.getPublicKeyBytes(this.ownerPubKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Filter{" +
|
||||
@ -285,14 +336,19 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
||||
",\n priceRelayNodes=" + priceRelayNodes +
|
||||
",\n preventPublicBtcNetwork=" + preventPublicBtcNetwork +
|
||||
",\n btcNodes=" + btcNodes +
|
||||
",\n extraDataMap=" + extraDataMap +
|
||||
",\n signatureAsBase64='" + signatureAsBase64 + '\'' +
|
||||
",\n signerPubKeyAsHex='" + signerPubKeyAsHex + '\'' +
|
||||
",\n ownerPubKeyBytes=" + Utilities.bytesAsHexString(ownerPubKeyBytes) +
|
||||
",\n disableDao=" + disableDao +
|
||||
",\n disableDaoBelowVersion='" + disableDaoBelowVersion + '\'' +
|
||||
",\n disableTradeBelowVersion='" + disableTradeBelowVersion + '\'' +
|
||||
",\n mediators=" + mediators +
|
||||
",\n refundAgents=" + refundAgents +
|
||||
",\n bannedSignerPubKeys=" + bannedSignerPubKeys +
|
||||
",\n bannedAccountWitnessSignerPubKeys=" + bannedAccountWitnessSignerPubKeys +
|
||||
",\n bannedPrivilegedDevPubKeys=" + bannedPrivilegedDevPubKeys +
|
||||
",\n btcFeeReceiverAddresses=" + btcFeeReceiverAddresses +
|
||||
",\n creationDate=" + creationDate +
|
||||
",\n extraDataMap=" + extraDataMap +
|
||||
"\n}";
|
||||
}
|
||||
}
|
||||
|
@ -29,9 +29,7 @@ import bisq.network.p2p.P2PService;
|
||||
import bisq.network.p2p.P2PServiceListener;
|
||||
import bisq.network.p2p.storage.HashMapChangedListener;
|
||||
import bisq.network.p2p.storage.payload.ProtectedStorageEntry;
|
||||
import bisq.network.p2p.storage.payload.ProtectedStoragePayload;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.DevEnv;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.config.Config;
|
||||
@ -39,7 +37,7 @@ import bisq.common.config.ConfigFileEditor;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
@ -47,33 +45,36 @@ import javax.inject.Named;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
import java.security.SignatureException;
|
||||
import org.spongycastle.util.encoders.Base64;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.bitcoinj.core.Utils.HEX;
|
||||
|
||||
/**
|
||||
* We only support one active filter, if we receive multiple we use the one with the more recent creationDate.
|
||||
*/
|
||||
@Slf4j
|
||||
public class FilterManager {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FilterManager.class);
|
||||
|
||||
public static final String BANNED_PRICE_RELAY_NODES = "bannedPriceRelayNodes";
|
||||
public static final String BANNED_SEED_NODES = "bannedSeedNodes";
|
||||
public static final String BANNED_BTC_NODES = "bannedBtcNodes";
|
||||
private static final String BANNED_PRICE_RELAY_NODES = "bannedPriceRelayNodes";
|
||||
private static final String BANNED_SEED_NODES = "bannedSeedNodes";
|
||||
private static final String BANNED_BTC_NODES = "bannedBtcNodes";
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -90,16 +91,15 @@ public class FilterManager {
|
||||
private final Preferences preferences;
|
||||
private final ConfigFileEditor configFileEditor;
|
||||
private final ProvidersRepository providersRepository;
|
||||
private boolean ignoreDevMsg;
|
||||
private final boolean ignoreDevMsg;
|
||||
private final ObjectProperty<Filter> filterProperty = new SimpleObjectProperty<>();
|
||||
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final String pubKeyAsHex;
|
||||
private final List<String> publicKeys;
|
||||
private ECKey filterSigningKey;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, Initialization
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
@ -118,48 +118,53 @@ public class FilterManager {
|
||||
this.configFileEditor = new ConfigFileEditor(config.configFile);
|
||||
this.providersRepository = providersRepository;
|
||||
this.ignoreDevMsg = ignoreDevMsg;
|
||||
pubKeyAsHex = useDevPrivilegeKeys ?
|
||||
DevEnv.DEV_PRIVILEGE_PUB_KEY :
|
||||
"022ac7b7766b0aedff82962522c2c14fb8d1961dabef6e5cfd10edc679456a32f1";
|
||||
|
||||
publicKeys = useDevPrivilegeKeys ?
|
||||
Collections.singletonList(DevEnv.DEV_PRIVILEGE_PUB_KEY) :
|
||||
List.of("0358d47858acdc41910325fce266571540681ef83a0d6fedce312bef9810793a27",
|
||||
"029340c3e7d4bb0f9e651b5f590b434fecb6175aeaa57145c7804ff05d210e534f",
|
||||
"034dc7530bf66ffd9580aa98031ea9a18ac2d269f7c56c0e71eca06105b9ed69f9");
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void onAllServicesInitialized() {
|
||||
if (!ignoreDevMsg) {
|
||||
|
||||
final List<ProtectedStorageEntry> list = new ArrayList<>(p2PService.getP2PDataStorage().getMap().values());
|
||||
list.forEach(e -> {
|
||||
final ProtectedStoragePayload protectedStoragePayload = e.getProtectedStoragePayload();
|
||||
if (protectedStoragePayload instanceof Filter)
|
||||
addFilter((Filter) protectedStoragePayload);
|
||||
});
|
||||
|
||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(Collection<ProtectedStorageEntry> protectedStorageEntries) {
|
||||
protectedStorageEntries.forEach(protectedStorageEntry -> {
|
||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof Filter) {
|
||||
Filter filter = (Filter) protectedStorageEntry.getProtectedStoragePayload();
|
||||
boolean wasValid = addFilter(filter);
|
||||
if (!wasValid) {
|
||||
UserThread.runAfter(() -> p2PService.getP2PDataStorage().removeInvalidProtectedStorageEntry(protectedStorageEntry), 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(Collection<ProtectedStorageEntry> protectedStorageEntries) {
|
||||
protectedStorageEntries.forEach(protectedStorageEntry -> {
|
||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof Filter) {
|
||||
Filter filter = (Filter) protectedStorageEntry.getProtectedStoragePayload();
|
||||
if (verifySignature(filter) && getFilter().equals(filter))
|
||||
resetFilters();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (ignoreDevMsg) {
|
||||
return;
|
||||
}
|
||||
|
||||
p2PService.getP2PDataStorage().getMap().values().stream()
|
||||
.map(ProtectedStorageEntry::getProtectedStoragePayload)
|
||||
.filter(protectedStoragePayload -> protectedStoragePayload instanceof Filter)
|
||||
.map(protectedStoragePayload -> (Filter) protectedStoragePayload)
|
||||
.forEach(this::onFilterAddedFromNetwork);
|
||||
|
||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(Collection<ProtectedStorageEntry> protectedStorageEntries) {
|
||||
protectedStorageEntries.stream()
|
||||
.filter(protectedStorageEntry -> protectedStorageEntry.getProtectedStoragePayload() instanceof Filter)
|
||||
.forEach(protectedStorageEntry -> {
|
||||
Filter filter = (Filter) protectedStorageEntry.getProtectedStoragePayload();
|
||||
onFilterAddedFromNetwork(filter);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(Collection<ProtectedStorageEntry> protectedStorageEntries) {
|
||||
protectedStorageEntries.stream()
|
||||
.filter(protectedStorageEntry -> protectedStorageEntry.getProtectedStoragePayload() instanceof Filter)
|
||||
.forEach(protectedStorageEntry -> {
|
||||
Filter filter = (Filter) protectedStorageEntry.getProtectedStoragePayload();
|
||||
onFilterRemovedFromNetwork(filter);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
p2PService.addP2PServiceListener(new P2PServiceListener() {
|
||||
@Override
|
||||
public void onDataReceived() {
|
||||
@ -175,12 +180,12 @@ public class FilterManager {
|
||||
|
||||
@Override
|
||||
public void onUpdatedDataReceived() {
|
||||
// We should have received all data at that point and if the filers were not set we
|
||||
// clean up as it might be that we missed the filter remove message if we have not been online.
|
||||
UserThread.runAfter(() -> {
|
||||
if (filterProperty.get() == null)
|
||||
resetFilters();
|
||||
}, 1);
|
||||
// We should have received all data at that point and if the filters were not set we
|
||||
// clean up the persisted banned nodes in the options file as it might be that we missed the filter
|
||||
// remove message if we have not been online.
|
||||
if (filterProperty.get() == null) {
|
||||
clearBannedNodes();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,54 +206,94 @@ public class FilterManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void resetFilters() {
|
||||
saveBannedNodes(BANNED_BTC_NODES, null);
|
||||
saveBannedNodes(BANNED_SEED_NODES, null);
|
||||
saveBannedNodes(BANNED_PRICE_RELAY_NODES, null);
|
||||
|
||||
if (providersRepository.getBannedNodes() != null)
|
||||
providersRepository.applyBannedNodes(null);
|
||||
|
||||
filterProperty.set(null);
|
||||
}
|
||||
|
||||
private boolean addFilter(Filter filter) {
|
||||
if (verifySignature(filter)) {
|
||||
// Seed nodes are requested at startup before we get the filter so we only apply the banned
|
||||
// nodes at the next startup and don't update the list in the P2P network domain.
|
||||
// We persist it to the property file which is read before any other initialisation.
|
||||
saveBannedNodes(BANNED_SEED_NODES, filter.getSeedNodes());
|
||||
saveBannedNodes(BANNED_BTC_NODES, filter.getBtcNodes());
|
||||
|
||||
// Banned price relay nodes we can apply at runtime
|
||||
final List<String> priceRelayNodes = filter.getPriceRelayNodes();
|
||||
saveBannedNodes(BANNED_PRICE_RELAY_NODES, priceRelayNodes);
|
||||
|
||||
providersRepository.applyBannedNodes(priceRelayNodes);
|
||||
|
||||
filterProperty.set(filter);
|
||||
listeners.forEach(e -> e.onFilterAdded(filter));
|
||||
|
||||
if (filter.isPreventPublicBtcNetwork() &&
|
||||
preferences.getBitcoinNodesOptionOrdinal() == BtcNodes.BitcoinNodesOption.PUBLIC.ordinal())
|
||||
preferences.setBitcoinNodesOptionOrdinal(BtcNodes.BitcoinNodesOption.PROVIDED.ordinal());
|
||||
return true;
|
||||
} else {
|
||||
public boolean isPrivilegedDevPubKeyBanned(String pubKeyAsHex) {
|
||||
Filter filter = getFilter();
|
||||
if (filter == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return filter.getBannedPrivilegedDevPubKeys().contains(pubKeyAsHex);
|
||||
}
|
||||
|
||||
private void saveBannedNodes(String optionName, List<String> bannedNodes) {
|
||||
if (bannedNodes != null)
|
||||
configFileEditor.setOption(optionName, String.join(",", bannedNodes));
|
||||
else
|
||||
configFileEditor.clearOption(optionName);
|
||||
public boolean canAddDevFilter(String privKeyString) {
|
||||
if (privKeyString == null || privKeyString.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!isValidDevPrivilegeKey(privKeyString)) {
|
||||
log.warn("Key in invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
ECKey ecKeyFromPrivate = toECKey(privKeyString);
|
||||
String pubKeyAsHex = getPubKeyAsHex(ecKeyFromPrivate);
|
||||
if (isPrivilegedDevPubKeyBanned(pubKeyAsHex)) {
|
||||
log.warn("Pub key is banned.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getSignerPubKeyAsHex(String privKeyString) {
|
||||
ECKey ecKey = toECKey(privKeyString);
|
||||
return getPubKeyAsHex(ecKey);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
public void addDevFilter(Filter filterWithoutSig, String privKeyString) {
|
||||
setFilterSigningKey(privKeyString);
|
||||
String signatureAsBase64 = getSignature(filterWithoutSig);
|
||||
Filter filterWithSig = Filter.cloneWithSig(filterWithoutSig, signatureAsBase64);
|
||||
user.setDevelopersFilter(filterWithSig);
|
||||
|
||||
p2PService.addProtectedStorageEntry(filterWithSig);
|
||||
}
|
||||
|
||||
public boolean canRemoveDevFilter(String privKeyString) {
|
||||
if (privKeyString == null || privKeyString.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Filter developersFilter = getDevFilter();
|
||||
if (developersFilter == null) {
|
||||
log.warn("There is no persisted dev filter to be removed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isValidDevPrivilegeKey(privKeyString)) {
|
||||
log.warn("Key in invalid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ECKey ecKeyFromPrivate = toECKey(privKeyString);
|
||||
String pubKeyAsHex = getPubKeyAsHex(ecKeyFromPrivate);
|
||||
if (!developersFilter.getSignerPubKeyAsHex().equals(pubKeyAsHex)) {
|
||||
log.warn("pubKeyAsHex derived from private key does not match filterSignerPubKey. " +
|
||||
"filterSignerPubKey={}, pubKeyAsHex derived from private key={}",
|
||||
developersFilter.getSignerPubKeyAsHex(), pubKeyAsHex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isPrivilegedDevPubKeyBanned(pubKeyAsHex)) {
|
||||
log.warn("Pub key is banned.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removeDevFilter(String privKeyString) {
|
||||
setFilterSigningKey(privKeyString);
|
||||
Filter filterWithSig = user.getDevelopersFilter();
|
||||
if (filterWithSig == null) {
|
||||
// Should not happen as UI button is deactivated in that case
|
||||
return;
|
||||
}
|
||||
|
||||
if (p2PService.removeData(filterWithSig)) {
|
||||
user.setDevelopersFilter(null);
|
||||
} else {
|
||||
log.warn("Removing dev filter from network failed");
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(Listener listener) {
|
||||
listeners.add(listener);
|
||||
@ -263,85 +308,15 @@ public class FilterManager {
|
||||
return filterProperty.get();
|
||||
}
|
||||
|
||||
public boolean addFilterMessageIfKeyIsValid(Filter filter, String privKeyString) {
|
||||
// if there is a previous message we remove that first
|
||||
if (user.getDevelopersFilter() != null)
|
||||
removeFilterMessageIfKeyIsValid(privKeyString);
|
||||
|
||||
boolean isKeyValid = isKeyValid(privKeyString);
|
||||
if (isKeyValid) {
|
||||
signAndAddSignatureToFilter(filter);
|
||||
user.setDevelopersFilter(filter);
|
||||
|
||||
boolean result = p2PService.addProtectedStorageEntry(filter);
|
||||
if (result)
|
||||
log.trace("Add filter to network was successful. FilterMessage = {}", filter);
|
||||
|
||||
}
|
||||
return isKeyValid;
|
||||
}
|
||||
|
||||
public boolean removeFilterMessageIfKeyIsValid(String privKeyString) {
|
||||
if (isKeyValid(privKeyString)) {
|
||||
Filter filter = user.getDevelopersFilter();
|
||||
if (filter == null) {
|
||||
log.warn("Developers filter is null");
|
||||
} else if (p2PService.removeData(filter)) {
|
||||
log.trace("Remove filter from network was successful. FilterMessage = {}", filter);
|
||||
user.setDevelopersFilter(null);
|
||||
} else {
|
||||
log.warn("Filter remove failed");
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isKeyValid(String privKeyString) {
|
||||
try {
|
||||
filterSigningKey = ECKey.fromPrivate(new BigInteger(1, HEX.decode(privKeyString)));
|
||||
return pubKeyAsHex.equals(Utils.HEX.encode(filterSigningKey.getPubKey()));
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void signAndAddSignatureToFilter(Filter filter) {
|
||||
filter.setSigAndPubKey(filterSigningKey.signMessage(getHexFromData(filter)), keyRing.getSignatureKeyPair().getPublic());
|
||||
}
|
||||
|
||||
private boolean verifySignature(Filter filter) {
|
||||
try {
|
||||
ECKey.fromPublicOnly(HEX.decode(pubKeyAsHex)).verifyMessage(getHexFromData(filter), filter.getSignatureAsBase64());
|
||||
return true;
|
||||
} catch (SignatureException e) {
|
||||
log.warn("verifySignature failed. filter={}", filter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't use full data from Filter as we are only interested in the filter data not the sig and keys
|
||||
private String getHexFromData(Filter filter) {
|
||||
protobuf.Filter.Builder builder = protobuf.Filter.newBuilder()
|
||||
.addAllBannedOfferIds(filter.getBannedOfferIds())
|
||||
.addAllBannedNodeAddress(filter.getBannedNodeAddress())
|
||||
.addAllBannedPaymentAccounts(filter.getBannedPaymentAccounts().stream()
|
||||
.map(PaymentAccountFilter::toProtoMessage)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Filter getDevelopersFilter() {
|
||||
public Filter getDevFilter() {
|
||||
return user.getDevelopersFilter();
|
||||
}
|
||||
|
||||
public PublicKey getOwnerPubKey() {
|
||||
return keyRing.getSignatureKeyPair().getPublic();
|
||||
}
|
||||
|
||||
public boolean isCurrencyBanned(String currencyCode) {
|
||||
return getFilter() != null &&
|
||||
getFilter().getBannedCurrencies() != null &&
|
||||
@ -396,8 +371,8 @@ public class FilterManager {
|
||||
return requireUpdateToNewVersion;
|
||||
}
|
||||
|
||||
public boolean isPeersPaymentAccountDataAreBanned(PaymentAccountPayload paymentAccountPayload,
|
||||
PaymentAccountFilter[] appliedPaymentAccountFilter) {
|
||||
public boolean arePeersPaymentAccountDataBanned(PaymentAccountPayload paymentAccountPayload,
|
||||
PaymentAccountFilter[] appliedPaymentAccountFilter) {
|
||||
return getFilter() != null &&
|
||||
getFilter().getBannedPaymentAccounts().stream()
|
||||
.anyMatch(paymentAccountFilter -> {
|
||||
@ -419,11 +394,183 @@ public class FilterManager {
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isSignerPubKeyBanned(String signerPubKeyAsHex) {
|
||||
public boolean isWitnessSignerPubKeyBanned(String witnessSignerPubKeyAsHex) {
|
||||
return getFilter() != null &&
|
||||
getFilter().getBannedSignerPubKeys() != null &&
|
||||
getFilter().getBannedSignerPubKeys().stream()
|
||||
.anyMatch(e -> e.equals(signerPubKeyAsHex));
|
||||
getFilter().getBannedAccountWitnessSignerPubKeys() != null &&
|
||||
getFilter().getBannedAccountWitnessSignerPubKeys().stream()
|
||||
.anyMatch(e -> e.equals(witnessSignerPubKeyAsHex));
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void onFilterAddedFromNetwork(Filter newFilter) {
|
||||
Filter currentFilter = getFilter();
|
||||
|
||||
if (!isFilterPublicKeyInList(newFilter)) {
|
||||
log.warn("isFilterPublicKeyInList failed. Filter={}", newFilter);
|
||||
return;
|
||||
}
|
||||
if (!isSignatureValid(newFilter)) {
|
||||
log.warn("verifySignature failed. Filter={}", newFilter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentFilter != null) {
|
||||
if (currentFilter.getCreationDate() > newFilter.getCreationDate()) {
|
||||
log.warn("We received a new filter from the network but the creation date is older than the " +
|
||||
"filter we have already. We ignore the new filter.\n" +
|
||||
"New filer={}\n" +
|
||||
"Old filter={}",
|
||||
newFilter, filterProperty.get());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPrivilegedDevPubKeyBanned(newFilter.getSignerPubKeyAsHex())) {
|
||||
log.warn("Pub key of filter is banned. currentFilter={}, newFilter={}", currentFilter, newFilter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Our new filter is newer so we apply it.
|
||||
// We do not require strict guarantees here (e.g. clocks not synced) as only trusted developers have the key
|
||||
// for deploying filters and this is only in place to avoid unintended situations of multiple filters
|
||||
// from multiple devs or if same dev publishes new filter from different app without the persisted devFilter.
|
||||
filterProperty.set(newFilter);
|
||||
|
||||
// Seed nodes are requested at startup before we get the filter so we only apply the banned
|
||||
// nodes at the next startup and don't update the list in the P2P network domain.
|
||||
// We persist it to the property file which is read before any other initialisation.
|
||||
saveBannedNodes(BANNED_SEED_NODES, newFilter.getSeedNodes());
|
||||
saveBannedNodes(BANNED_BTC_NODES, newFilter.getBtcNodes());
|
||||
|
||||
// Banned price relay nodes we can apply at runtime
|
||||
List<String> priceRelayNodes = newFilter.getPriceRelayNodes();
|
||||
saveBannedNodes(BANNED_PRICE_RELAY_NODES, priceRelayNodes);
|
||||
|
||||
//TODO should be moved to client with listening on onFilterAdded
|
||||
providersRepository.applyBannedNodes(priceRelayNodes);
|
||||
|
||||
//TODO should be moved to client with listening on onFilterAdded
|
||||
if (newFilter.isPreventPublicBtcNetwork() &&
|
||||
preferences.getBitcoinNodesOptionOrdinal() == BtcNodes.BitcoinNodesOption.PUBLIC.ordinal()) {
|
||||
preferences.setBitcoinNodesOptionOrdinal(BtcNodes.BitcoinNodesOption.PROVIDED.ordinal());
|
||||
}
|
||||
|
||||
listeners.forEach(e -> e.onFilterAdded(newFilter));
|
||||
}
|
||||
|
||||
private void onFilterRemovedFromNetwork(Filter filter) {
|
||||
if (!isFilterPublicKeyInList(filter)) {
|
||||
log.warn("isFilterPublicKeyInList failed. Filter={}", filter);
|
||||
return;
|
||||
}
|
||||
if (!isSignatureValid(filter)) {
|
||||
log.warn("verifySignature failed. Filter={}", filter);
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't check for banned filter as we want to remove a banned filter anyway.
|
||||
|
||||
if (!filterProperty.get().equals(filter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearBannedNodes();
|
||||
|
||||
if (filter.equals(user.getDevelopersFilter())) {
|
||||
user.setDevelopersFilter(null);
|
||||
}
|
||||
filterProperty.set(null);
|
||||
}
|
||||
|
||||
// Clears options files from banned nodes
|
||||
private void clearBannedNodes() {
|
||||
saveBannedNodes(BANNED_BTC_NODES, null);
|
||||
saveBannedNodes(BANNED_SEED_NODES, null);
|
||||
saveBannedNodes(BANNED_PRICE_RELAY_NODES, null);
|
||||
|
||||
if (providersRepository.getBannedNodes() != null) {
|
||||
providersRepository.applyBannedNodes(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveBannedNodes(String optionName, List<String> bannedNodes) {
|
||||
if (bannedNodes != null)
|
||||
configFileEditor.setOption(optionName, String.join(",", bannedNodes));
|
||||
else
|
||||
configFileEditor.clearOption(optionName);
|
||||
}
|
||||
|
||||
private boolean isValidDevPrivilegeKey(String privKeyString) {
|
||||
try {
|
||||
ECKey filterSigningKey = toECKey(privKeyString);
|
||||
String pubKeyAsHex = getPubKeyAsHex(filterSigningKey);
|
||||
return isPublicKeyInList(pubKeyAsHex);
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setFilterSigningKey(String privKeyString) {
|
||||
this.filterSigningKey = toECKey(privKeyString);
|
||||
}
|
||||
|
||||
private String getSignature(Filter filterWithoutSig) {
|
||||
Sha256Hash hash = getSha256Hash(filterWithoutSig);
|
||||
ECKey.ECDSASignature ecdsaSignature = filterSigningKey.sign(hash);
|
||||
byte[] encodeToDER = ecdsaSignature.encodeToDER();
|
||||
return new String(Base64.encode(encodeToDER), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private boolean isFilterPublicKeyInList(Filter filter) {
|
||||
String signerPubKeyAsHex = filter.getSignerPubKeyAsHex();
|
||||
if (!isPublicKeyInList(signerPubKeyAsHex)) {
|
||||
log.warn("signerPubKeyAsHex from filter is not part of our pub key list. filter={}, publicKeys={}", filter, publicKeys);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isPublicKeyInList(String pubKeyAsHex) {
|
||||
boolean isPublicKeyInList = publicKeys.contains(pubKeyAsHex);
|
||||
if (!isPublicKeyInList) {
|
||||
log.warn("pubKeyAsHex is not part of our pub key list. pubKeyAsHex={}, publicKeys={}", pubKeyAsHex, publicKeys);
|
||||
}
|
||||
return isPublicKeyInList;
|
||||
}
|
||||
|
||||
private boolean isSignatureValid(Filter filter) {
|
||||
try {
|
||||
Filter filterForSigVerification = Filter.cloneWithoutSig(filter);
|
||||
Sha256Hash hash = getSha256Hash(filterForSigVerification);
|
||||
|
||||
checkNotNull(filter.getSignatureAsBase64(), "filter.getSignatureAsBase64() must not be null");
|
||||
byte[] sigData = Base64.decode(filter.getSignatureAsBase64());
|
||||
ECKey.ECDSASignature ecdsaSignature = ECKey.ECDSASignature.decodeFromDER(sigData);
|
||||
|
||||
String signerPubKeyAsHex = filter.getSignerPubKeyAsHex();
|
||||
byte[] decode = HEX.decode(signerPubKeyAsHex);
|
||||
ECKey ecPubKey = ECKey.fromPublicOnly(decode);
|
||||
return ecPubKey.verify(hash, ecdsaSignature);
|
||||
} catch (Throwable e) {
|
||||
log.warn("verifySignature failed. filter={}", filter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private ECKey toECKey(String privKeyString) {
|
||||
return ECKey.fromPrivate(new BigInteger(1, HEX.decode(privKeyString)));
|
||||
}
|
||||
|
||||
private Sha256Hash getSha256Hash(Filter filter) {
|
||||
byte[] filterData = filter.toProtoMessage().toByteArray();
|
||||
return Sha256Hash.of(filterData);
|
||||
}
|
||||
|
||||
private String getPubKeyAsHex(ECKey ecKey) {
|
||||
return HEX.encode(ecKey.getPubKey());
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class ApplyFilter extends TradeTask {
|
||||
} else if (filterManager.isPaymentMethodBanned(trade.getOffer().getPaymentMethod())) {
|
||||
failed("Payment method is banned.\n" +
|
||||
"Payment method=" + trade.getOffer().getPaymentMethod().getId());
|
||||
} else if (filterManager.isPeersPaymentAccountDataAreBanned(paymentAccountPayload, appliedPaymentAccountFilter)) {
|
||||
} else if (filterManager.arePeersPaymentAccountDataBanned(paymentAccountPayload, appliedPaymentAccountFilter)) {
|
||||
failed("Other trader is banned by their trading account data.\n" +
|
||||
"paymentAccountPayload=" + paymentAccountPayload.getPaymentDetails() + "\n" +
|
||||
"banFilter=" + appliedPaymentAccountFilter[0].toString());
|
||||
|
@ -1169,8 +1169,8 @@ setting.about.support=Support Bisq
|
||||
setting.about.def=Bisq is not a company—it is a project open to the community. If you want to participate or support Bisq please follow the links below.
|
||||
setting.about.contribute=Contribute
|
||||
setting.about.providers=Data providers
|
||||
+setting.about.apisWithFee=Bisq uses Bisq Price Indices for Fiat and Altcoin market prices, and Bisq Mempool Nodes for mining fee estimation.
|
||||
+setting.about.apis=Bisq uses Bisq Price Indices for Fiat and Altcoin market prices.
|
||||
setting.about.apisWithFee=Bisq uses Bisq Price Indices for Fiat and Altcoin market prices, and Bisq Mempool Nodes for mining fee estimation.
|
||||
setting.about.apis=Bisq uses Bisq Price Indices for Fiat and Altcoin market prices.
|
||||
setting.about.pricesProvided=Market prices provided by
|
||||
setting.about.feeEstimation.label=Mining fee estimation provided by
|
||||
setting.about.versionDetails=Version details
|
||||
@ -2449,7 +2449,8 @@ 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.bannedAccountWitnessSignerPubKeys=Filtered account witness signer pub keys (comma sep. hex of pub keys)
|
||||
filterWindow.bannedPrivilegedDevPubKeys=Filtered privileged dev pub keys (comma sep. hex of pub keys)
|
||||
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)
|
||||
|
@ -397,14 +397,14 @@ public class SignedWitnessServiceTest {
|
||||
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);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(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);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(false);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
@ -434,14 +434,14 @@ public class SignedWitnessServiceTest {
|
||||
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);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(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);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(false);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertTrue(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
@ -484,21 +484,21 @@ public class SignedWitnessServiceTest {
|
||||
signedWitnessService.addToMap(sw3p);
|
||||
|
||||
// First account is banned, the other two are still signers
|
||||
when(filterManager.isSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(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);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(false);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(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);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner1PubKey))).thenReturn(true);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(Utilities.bytesAsHexString(witnessOwner2PubKey))).thenReturn(true);
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew1));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew2));
|
||||
assertFalse(signedWitnessService.isSignerAccountAgeWitness(aew3));
|
||||
|
@ -218,8 +218,8 @@ public class AccountAgeWitnessServiceTest {
|
||||
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(filterManager.arePeersPaymentAccountDataBanned(any(), any())).thenReturn(false);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(any())).thenReturn(false);
|
||||
|
||||
when(chargeBackRisk.hasChargebackRisk(any(), any())).thenReturn(true);
|
||||
|
||||
|
@ -53,13 +53,17 @@ public class UserPayloadModelVOTest {
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
"string",
|
||||
new byte[]{10, 0, 0},
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
null,
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList()));
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null));
|
||||
|
||||
vo.setRegisteredArbitrator(ArbitratorTest.getArbitratorMock());
|
||||
vo.setRegisteredMediator(MediatorTest.getMediatorMock());
|
||||
vo.setAcceptedArbitrators(Lists.newArrayList(ArbitratorTest.getArbitratorMock()));
|
||||
|
@ -22,6 +22,7 @@ import bisq.core.dao.governance.param.Param;
|
||||
import bisq.core.filter.Filter;
|
||||
import bisq.core.filter.FilterManager;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -98,10 +99,28 @@ public class FeeReceiverSelectorTest {
|
||||
}
|
||||
|
||||
private static Filter filterWithReceivers(List<String> btcFeeReceiverAddresses) {
|
||||
return new Filter(null, null, null, null,
|
||||
null, null, null, null,
|
||||
false, null, false, null,
|
||||
null, null, null, null,
|
||||
btcFeeReceiverAddresses);
|
||||
return new Filter(Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
false,
|
||||
Lists.newArrayList(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
btcFeeReceiverAddresses,
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
if (headLine == null)
|
||||
headLine = Res.get("filterWindow.headline");
|
||||
|
||||
width = 968;
|
||||
width = 1000;
|
||||
|
||||
createGridPane();
|
||||
|
||||
@ -87,7 +87,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
scrollPane.setContent(gridPane);
|
||||
scrollPane.setFitToWidth(true);
|
||||
scrollPane.setFitToHeight(true);
|
||||
scrollPane.setMaxHeight(1000);
|
||||
scrollPane.setMaxHeight(700);
|
||||
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
|
||||
addHeadLine();
|
||||
@ -112,90 +112,123 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
gridPane.getColumnConstraints().remove(1);
|
||||
gridPane.getColumnConstraints().get(0).setHalignment(HPos.LEFT);
|
||||
|
||||
InputTextField keyInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("shared.unlock"), 10);
|
||||
if (useDevPrivilegeKeys)
|
||||
keyInputTextField.setText(DevEnv.DEV_PRIVILEGE_PRIV_KEY);
|
||||
InputTextField keyTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("shared.unlock"), 10);
|
||||
if (useDevPrivilegeKeys) {
|
||||
keyTF.setText(DevEnv.DEV_PRIVILEGE_PRIV_KEY);
|
||||
}
|
||||
|
||||
InputTextField offerIdsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.offers"));
|
||||
InputTextField nodesInputTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.onions")).second;
|
||||
nodesInputTextField.setPromptText("E.g. zqnzx6o3nifef5df.onion:9999"); // Do not translate
|
||||
InputTextField paymentAccountFilterInputTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.accounts")).second;
|
||||
GridPane.setHalignment(paymentAccountFilterInputTextField, HPos.RIGHT);
|
||||
paymentAccountFilterInputTextField.setPromptText("E.g. PERFECT_MONEY|getAccountNr|12345"); // Do not translate
|
||||
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"));
|
||||
InputTextField btcFeeReceiverAddressesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.btcFeeReceiverAddresses"));
|
||||
InputTextField seedNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.seedNode"));
|
||||
InputTextField priceRelayNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.priceRelayNode"));
|
||||
InputTextField btcNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.btcNode"));
|
||||
CheckBox preventPublicBtcNetworkCheckBox = addLabelCheckBox(gridPane, ++rowIndex, Res.get("filterWindow.preventPublicBtcNetwork"));
|
||||
CheckBox disableDaoCheckBox = addLabelCheckBox(gridPane, ++rowIndex, Res.get("filterWindow.disableDao"));
|
||||
InputTextField disableDaoBelowVersionInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.disableDaoBelowVersion"));
|
||||
InputTextField disableTradeBelowVersionInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.disableTradeBelowVersion"));
|
||||
InputTextField offerIdsTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.offers"));
|
||||
InputTextField nodesTF = addTopLabelInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.onions")).second;
|
||||
nodesTF.setPromptText("E.g. zqnzx6o3nifef5df.onion:9999"); // Do not translate
|
||||
InputTextField paymentAccountFilterTF = addTopLabelInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.accounts")).second;
|
||||
GridPane.setHalignment(paymentAccountFilterTF, HPos.RIGHT);
|
||||
paymentAccountFilterTF.setPromptText("E.g. PERFECT_MONEY|getAccountNr|12345"); // Do not translate
|
||||
InputTextField bannedCurrenciesTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.bannedCurrencies"));
|
||||
InputTextField bannedPaymentMethodsTF = addTopLabelInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.bannedPaymentMethods")).second;
|
||||
bannedPaymentMethodsTF.setPromptText("E.g. PERFECT_MONEY"); // Do not translate
|
||||
InputTextField bannedAccountWitnessSignerPubKeysTF = addTopLabelInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.bannedAccountWitnessSignerPubKeys")).second;
|
||||
bannedAccountWitnessSignerPubKeysTF.setPromptText("E.g. 7f66117aa084e5a2c54fe17d29dd1fee2b241257"); // Do not translate
|
||||
InputTextField arbitratorsTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.arbitrators"));
|
||||
InputTextField mediatorsTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.mediators"));
|
||||
InputTextField refundAgentsTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.refundAgents"));
|
||||
InputTextField btcFeeReceiverAddressesTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.btcFeeReceiverAddresses"));
|
||||
InputTextField seedNodesTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.seedNode"));
|
||||
InputTextField priceRelayNodesTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.priceRelayNode"));
|
||||
InputTextField btcNodesTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.btcNode"));
|
||||
CheckBox preventPublicBtcNetworkCheckBox = addLabelCheckBox(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.preventPublicBtcNetwork"));
|
||||
CheckBox disableDaoCheckBox = addLabelCheckBox(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.disableDao"));
|
||||
InputTextField disableDaoBelowVersionTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.disableDaoBelowVersion"));
|
||||
InputTextField disableTradeBelowVersionTF = addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.disableTradeBelowVersion"));
|
||||
InputTextField bannedPrivilegedDevPubKeysTF = addTopLabelInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("filterWindow.bannedPrivilegedDevPubKeys")).second;
|
||||
|
||||
final Filter filter = filterManager.getDevelopersFilter();
|
||||
Filter filter = filterManager.getDevFilter();
|
||||
if (filter != null) {
|
||||
setupFieldFromList(offerIdsInputTextField, filter.getBannedOfferIds());
|
||||
setupFieldFromList(nodesInputTextField, filter.getBannedNodeAddress());
|
||||
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(btcFeeReceiverAddressesInputTextField, filter.getBtcFeeReceiverAddresses());
|
||||
setupFieldFromList(seedNodesInputTextField, filter.getSeedNodes());
|
||||
setupFieldFromList(priceRelayNodesInputTextField, filter.getPriceRelayNodes());
|
||||
setupFieldFromList(btcNodesInputTextField, filter.getBtcNodes());
|
||||
setupFieldFromList(offerIdsTF, filter.getBannedOfferIds());
|
||||
setupFieldFromList(nodesTF, filter.getBannedNodeAddress());
|
||||
setupFieldFromPaymentAccountFiltersList(paymentAccountFilterTF, filter.getBannedPaymentAccounts());
|
||||
setupFieldFromList(bannedCurrenciesTF, filter.getBannedCurrencies());
|
||||
setupFieldFromList(bannedPaymentMethodsTF, filter.getBannedPaymentMethods());
|
||||
setupFieldFromList(bannedAccountWitnessSignerPubKeysTF, filter.getBannedAccountWitnessSignerPubKeys());
|
||||
setupFieldFromList(arbitratorsTF, filter.getArbitrators());
|
||||
setupFieldFromList(mediatorsTF, filter.getMediators());
|
||||
setupFieldFromList(refundAgentsTF, filter.getRefundAgents());
|
||||
setupFieldFromList(btcFeeReceiverAddressesTF, filter.getBtcFeeReceiverAddresses());
|
||||
setupFieldFromList(seedNodesTF, filter.getSeedNodes());
|
||||
setupFieldFromList(priceRelayNodesTF, filter.getPriceRelayNodes());
|
||||
setupFieldFromList(btcNodesTF, filter.getBtcNodes());
|
||||
setupFieldFromList(bannedPrivilegedDevPubKeysTF, filter.getBannedPrivilegedDevPubKeys());
|
||||
|
||||
preventPublicBtcNetworkCheckBox.setSelected(filter.isPreventPublicBtcNetwork());
|
||||
disableDaoCheckBox.setSelected(filter.isDisableDao());
|
||||
disableDaoBelowVersionInputTextField.setText(filter.getDisableDaoBelowVersion());
|
||||
disableTradeBelowVersionInputTextField.setText(filter.getDisableTradeBelowVersion());
|
||||
disableDaoBelowVersionTF.setText(filter.getDisableDaoBelowVersion());
|
||||
disableTradeBelowVersionTF.setText(filter.getDisableTradeBelowVersion());
|
||||
}
|
||||
Button sendButton = new AutoTooltipButton(Res.get("filterWindow.add"));
|
||||
sendButton.setOnAction(e -> {
|
||||
if (filterManager.addFilterMessageIfKeyIsValid(
|
||||
new Filter(
|
||||
readAsList(offerIdsInputTextField),
|
||||
readAsList(nodesInputTextField),
|
||||
readAsPaymentAccountFiltersList(paymentAccountFilterInputTextField),
|
||||
readAsList(bannedCurrenciesInputTextField),
|
||||
readAsList(bannedPaymentMethodsInputTextField),
|
||||
readAsList(arbitratorsInputTextField),
|
||||
readAsList(seedNodesInputTextField),
|
||||
readAsList(priceRelayNodesInputTextField),
|
||||
preventPublicBtcNetworkCheckBox.isSelected(),
|
||||
readAsList(btcNodesInputTextField),
|
||||
disableDaoCheckBox.isSelected(),
|
||||
disableDaoBelowVersionInputTextField.getText(),
|
||||
disableTradeBelowVersionInputTextField.getText(),
|
||||
readAsList(mediatorsInputTextField),
|
||||
readAsList(refundAgentsInputTextField),
|
||||
readAsList(bannedSignerPubKeysInputTextField),
|
||||
readAsList(btcFeeReceiverAddressesInputTextField)
|
||||
),
|
||||
keyInputTextField.getText())
|
||||
)
|
||||
hide();
|
||||
else
|
||||
new Popup().warning(Res.get("shared.invalidKey")).width(300).onClose(this::blurAgain).show();
|
||||
});
|
||||
|
||||
Button removeFilterMessageButton = new AutoTooltipButton(Res.get("filterWindow.remove"));
|
||||
removeFilterMessageButton.setDisable(filterManager.getDevFilter() == null);
|
||||
|
||||
Button sendButton = new AutoTooltipButton(Res.get("filterWindow.add"));
|
||||
sendButton.setOnAction(e -> {
|
||||
String privKeyString = keyTF.getText();
|
||||
if (filterManager.canAddDevFilter(privKeyString)) {
|
||||
String signerPubKeyAsHex = filterManager.getSignerPubKeyAsHex(privKeyString);
|
||||
Filter newFilter = new Filter(
|
||||
readAsList(offerIdsTF),
|
||||
readAsList(nodesTF),
|
||||
readAsPaymentAccountFiltersList(paymentAccountFilterTF),
|
||||
readAsList(bannedCurrenciesTF),
|
||||
readAsList(bannedPaymentMethodsTF),
|
||||
readAsList(arbitratorsTF),
|
||||
readAsList(seedNodesTF),
|
||||
readAsList(priceRelayNodesTF),
|
||||
preventPublicBtcNetworkCheckBox.isSelected(),
|
||||
readAsList(btcNodesTF),
|
||||
disableDaoCheckBox.isSelected(),
|
||||
disableDaoBelowVersionTF.getText(),
|
||||
disableTradeBelowVersionTF.getText(),
|
||||
readAsList(mediatorsTF),
|
||||
readAsList(refundAgentsTF),
|
||||
readAsList(bannedAccountWitnessSignerPubKeysTF),
|
||||
readAsList(btcFeeReceiverAddressesTF),
|
||||
filterManager.getOwnerPubKey(),
|
||||
signerPubKeyAsHex,
|
||||
readAsList(bannedPrivilegedDevPubKeysTF)
|
||||
);
|
||||
|
||||
filterManager.addDevFilter(newFilter, privKeyString);
|
||||
removeFilterMessageButton.setDisable(filterManager.getDevFilter() == null);
|
||||
hide();
|
||||
} else {
|
||||
new Popup().warning(Res.get("shared.invalidKey")).onClose(this::blurAgain).show();
|
||||
}
|
||||
});
|
||||
|
||||
removeFilterMessageButton.setOnAction(e -> {
|
||||
if (keyInputTextField.getText().length() > 0) {
|
||||
if (filterManager.removeFilterMessageIfKeyIsValid(keyInputTextField.getText()))
|
||||
hide();
|
||||
else
|
||||
new Popup().warning(Res.get("shared.invalidKey")).width(300).onClose(this::blurAgain).show();
|
||||
String privKeyString = keyTF.getText();
|
||||
if (filterManager.canRemoveDevFilter(privKeyString)) {
|
||||
filterManager.removeDevFilter(privKeyString);
|
||||
hide();
|
||||
} else {
|
||||
new Popup().warning(Res.get("shared.invalidKey")).onClose(this::blurAgain).show();
|
||||
}
|
||||
});
|
||||
|
||||
@ -215,13 +248,13 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
||||
|
||||
private void setupFieldFromList(InputTextField field, List<String> values) {
|
||||
if (values != null)
|
||||
field.setText(values.stream().collect(Collectors.joining(", ")));
|
||||
field.setText(String.join(", ", values));
|
||||
}
|
||||
|
||||
private void setupFieldFromPaymentAccountFiltersList(InputTextField field, List<PaymentAccountFilter> values) {
|
||||
if (values != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
values.stream().forEach(e -> {
|
||||
values.forEach(e -> {
|
||||
if (e != null && e.getPaymentMethodId() != null) {
|
||||
sb
|
||||
.append(e.getPaymentMethodId())
|
||||
|
@ -638,6 +638,9 @@ message Filter {
|
||||
repeated string refundAgents = 18;
|
||||
repeated string bannedSignerPubKeys = 19;
|
||||
repeated string btc_fee_receiver_addresses = 20;
|
||||
int64 creation_date = 21;
|
||||
string signer_pub_key_as_hex = 22;
|
||||
repeated string bannedPrivilegedDevPubKeys = 23;
|
||||
}
|
||||
|
||||
// not used anymore from v0.6 on. But leave it for receiving TradeStatistics objects from older
|
||||
|
Loading…
Reference in New Issue
Block a user