mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-25 07:27:18 +01:00
Merge branch 'dispute-agents-sign-summary' into dispute-agent-branch
This commit is contained in:
commit
f46a991101
17 changed files with 352 additions and 49 deletions
|
@ -48,6 +48,7 @@ import bisq.network.p2p.SendMailboxMessageListener;
|
|||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.handlers.FaultHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
@ -63,6 +64,8 @@ import javafx.beans.property.IntegerProperty;
|
|||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.security.KeyPair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
@ -90,6 +93,8 @@ public abstract class DisputeManager<T extends DisputeList<? extends DisputeList
|
|||
|
||||
@Getter
|
||||
protected final ObservableList<Dispute> disputesWithInvalidDonationAddress = FXCollections.observableArrayList();
|
||||
@Getter
|
||||
private final KeyPair signatureKeyPair;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -104,7 +109,7 @@ public abstract class DisputeManager<T extends DisputeList<? extends DisputeList
|
|||
ClosedTradableManager closedTradableManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
DaoFacade daoFacade,
|
||||
PubKeyRing pubKeyRing,
|
||||
KeyRing keyRing,
|
||||
DisputeListService<T> disputeListService,
|
||||
PriceFeedService priceFeedService) {
|
||||
super(p2PService, walletsSetup);
|
||||
|
@ -115,7 +120,8 @@ public abstract class DisputeManager<T extends DisputeList<? extends DisputeList
|
|||
this.closedTradableManager = closedTradableManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.daoFacade = daoFacade;
|
||||
this.pubKeyRing = pubKeyRing;
|
||||
this.pubKeyRing = keyRing.getPubKeyRing();
|
||||
signatureKeyPair = keyRing.getSignatureKeyPair();
|
||||
this.disputeListService = disputeListService;
|
||||
this.priceFeedService = priceFeedService;
|
||||
}
|
||||
|
@ -267,7 +273,6 @@ public abstract class DisputeManager<T extends DisputeList<? extends DisputeList
|
|||
return disputeList.stream().filter(e -> e.getTradeId().equals(tradeId)).findAny();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Message handler
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -646,7 +651,7 @@ public abstract class DisputeManager<T extends DisputeList<? extends DisputeList
|
|||
}
|
||||
|
||||
// dispute agent send result to trader
|
||||
public void sendDisputeResultMessage(DisputeResult disputeResult, Dispute dispute, String text) {
|
||||
public void sendDisputeResultMessage(DisputeResult disputeResult, Dispute dispute, String summaryText) {
|
||||
T disputeList = getDisputeList();
|
||||
if (disputeList == null) {
|
||||
log.warn("disputes is null");
|
||||
|
@ -658,7 +663,7 @@ public abstract class DisputeManager<T extends DisputeList<? extends DisputeList
|
|||
dispute.getTradeId(),
|
||||
dispute.getTraderPubKeyRing().hashCode(),
|
||||
false,
|
||||
text,
|
||||
summaryText,
|
||||
p2PService.getAddress());
|
||||
|
||||
disputeResult.setChatMessage(chatMessage);
|
||||
|
|
|
@ -54,6 +54,7 @@ import bisq.network.p2p.SendMailboxMessageListener;
|
|||
import bisq.common.Timer;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
|
@ -90,11 +91,11 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
ClosedTradableManager closedTradableManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
DaoFacade daoFacade,
|
||||
PubKeyRing pubKeyRing,
|
||||
KeyRing keyRing,
|
||||
ArbitrationDisputeListService arbitrationDisputeListService,
|
||||
PriceFeedService priceFeedService) {
|
||||
super(p2PService, tradeWalletService, walletService, walletsSetup, tradeManager, closedTradableManager,
|
||||
openOfferManager, daoFacade, pubKeyRing, arbitrationDisputeListService, priceFeedService);
|
||||
openOfferManager, daoFacade, keyRing, arbitrationDisputeListService, priceFeedService);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ import bisq.network.p2p.P2PService;
|
|||
import bisq.common.Timer;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.handlers.ErrorMessageHandler;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
|
@ -82,11 +82,11 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
|||
ClosedTradableManager closedTradableManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
DaoFacade daoFacade,
|
||||
PubKeyRing pubKeyRing,
|
||||
KeyRing keyRing,
|
||||
MediationDisputeListService mediationDisputeListService,
|
||||
PriceFeedService priceFeedService) {
|
||||
super(p2PService, tradeWalletService, walletService, walletsSetup, tradeManager, closedTradableManager,
|
||||
openOfferManager, daoFacade, pubKeyRing, mediationDisputeListService, priceFeedService);
|
||||
openOfferManager, daoFacade, keyRing, mediationDisputeListService, priceFeedService);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -45,7 +45,7 @@ import bisq.network.p2p.P2PService;
|
|||
import bisq.common.Timer;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.Version;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
@ -76,11 +76,11 @@ public final class RefundManager extends DisputeManager<RefundDisputeList> {
|
|||
ClosedTradableManager closedTradableManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
DaoFacade daoFacade,
|
||||
PubKeyRing pubKeyRing,
|
||||
KeyRing keyRing,
|
||||
RefundDisputeListService refundDisputeListService,
|
||||
PriceFeedService priceFeedService) {
|
||||
super(p2PService, tradeWalletService, walletService, walletsSetup, tradeManager, closedTradableManager,
|
||||
openOfferManager, daoFacade, pubKeyRing, refundDisputeListService, priceFeedService);
|
||||
openOfferManager, daoFacade, keyRing, refundDisputeListService, priceFeedService);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1007,11 +1007,24 @@ support.tab.legacyArbitration.support=Legacy Arbitration
|
|||
support.tab.ArbitratorsSupportTickets={0}'s tickets
|
||||
support.filter=Search disputes
|
||||
support.filter.prompt=Enter trade ID, date, onion address or account data
|
||||
|
||||
support.sigCheck.button=Verify result
|
||||
support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the \
|
||||
mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can \
|
||||
check with this tool if the signature of the mediator or arbitrator matches the summary message.
|
||||
support.sigCheck.popup.header=Verify dispute result signature
|
||||
support.sigCheck.popup.msg.label=Summary message
|
||||
support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute
|
||||
support.sigCheck.popup.result=Validation result
|
||||
support.sigCheck.popup.success=Signature is valid
|
||||
support.sigCheck.popup.failed=Signature verification failed
|
||||
support.sigCheck.popup.invalidFormat=Message is not of expected format. Copy & paste summary message from dispute.
|
||||
|
||||
support.reOpenByTrader.prompt=Are you sure you want to re-open the dispute?
|
||||
support.reOpenButton.label=Re-open dispute
|
||||
support.sendNotificationButton.label=Send private notification
|
||||
support.reportButton.label=Generate report
|
||||
support.fullReportButton.label=Get text dump of all disputes
|
||||
support.reOpenButton.label=Re-open
|
||||
support.sendNotificationButton.label=Private notification
|
||||
support.reportButton.label=Report
|
||||
support.fullReportButton.label=All disputes
|
||||
support.noTickets=There are no open tickets
|
||||
support.sendingMessage=Sending Message...
|
||||
support.receiverNotOnline=Receiver is not online. Message is saved to their mailbox.
|
||||
|
@ -2446,15 +2459,25 @@ disputeSummaryWindow.reason.TRADE_ALREADY_SETTLED=Trade already settled
|
|||
disputeSummaryWindow.summaryNotes=Summary notes
|
||||
disputeSummaryWindow.addSummaryNotes=Add summary notes
|
||||
disputeSummaryWindow.close.button=Close ticket
|
||||
disputeSummaryWindow.close.msg=Ticket closed on {0}\n\n\
|
||||
|
||||
# Do no change any line break or order of tokens as the structure is used for signature verification
|
||||
disputeSummaryWindow.close.msg=Ticket closed on {0}\n\
|
||||
{1} node address: {2}\n\n\
|
||||
Summary:\n\
|
||||
Payout amount for BTC buyer: {1}\n\
|
||||
Payout amount for BTC seller: {2}\n\n\
|
||||
Reason for dispute: {3}\n\n\
|
||||
Summary notes:\n{4}
|
||||
disputeSummaryWindow.close.nextStepsForMediation=\n\nNext steps:\n\
|
||||
Trade ID: {3}\n\
|
||||
Currency: {4}\n\
|
||||
Trade amount: {5}\n\
|
||||
Payout amount for BTC buyer: {6}\n\
|
||||
Payout amount for BTC seller: {7}\n\n\
|
||||
Reason for dispute: {8}\n\n\
|
||||
Summary notes:\n{9}\n
|
||||
|
||||
# Do no change any line break or order of tokens as the structure is used for signature verification
|
||||
disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3}
|
||||
|
||||
disputeSummaryWindow.close.nextStepsForMediation=\nNext steps:\n\
|
||||
Open trade and accept or reject suggestion from mediator
|
||||
disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\n\nNext steps:\n\
|
||||
disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\nNext steps:\n\
|
||||
No further action is required from you. If the arbitrator decided in your favor, you'll see a "Refund from arbitration" transaction in Funds/Transactions
|
||||
disputeSummaryWindow.close.closePeer=You need to close also the trading peers ticket!
|
||||
disputeSummaryWindow.close.txDetails.headline=Publish refund transaction
|
||||
|
|
|
@ -23,6 +23,7 @@ import bisq.desktop.components.BisqTextArea;
|
|||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.main.overlays.Overlay;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.support.dispute.DisputeSummaryVerification;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
|
@ -88,8 +89,7 @@ import java.util.Date;
|
|||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.add2ButtonsWithBox;
|
||||
import static bisq.desktop.util.FormBuilder.addConfirmationLabelLabel;
|
||||
|
@ -97,8 +97,9 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|||
import static bisq.desktop.util.FormBuilder.addTopLabelWithVBox;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Slf4j
|
||||
public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
||||
private static final Logger log = LoggerFactory.getLogger(DisputeSummaryWindow.class);
|
||||
|
||||
|
||||
private final CoinFormatter formatter;
|
||||
private final MediationManager mediationManager;
|
||||
|
@ -109,7 +110,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
private final FeeService feeService;
|
||||
private final DaoFacade daoFacade;
|
||||
private Dispute dispute;
|
||||
private Optional<Runnable> finalizeDisputeHandlerOptional = Optional.<Runnable>empty();
|
||||
private Optional<Runnable> finalizeDisputeHandlerOptional = Optional.empty();
|
||||
private ToggleGroup tradeAmountToggleGroup, reasonToggleGroup;
|
||||
private DisputeResult disputeResult;
|
||||
private RadioButton buyerGetsTradeAmountRadioButton, sellerGetsTradeAmountRadioButton,
|
||||
|
@ -227,7 +228,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
else
|
||||
disputeResult = dispute.getDisputeResultProperty().get();
|
||||
|
||||
peersDisputeOptional = getDisputeManager(dispute).getDisputesAsObservableList().stream()
|
||||
peersDisputeOptional = checkNotNull(getDisputeManager(dispute)).getDisputesAsObservableList().stream()
|
||||
.filter(d -> dispute.getTradeId().equals(d.getTradeId()) && dispute.getTraderId() != d.getTraderId())
|
||||
.findFirst();
|
||||
|
||||
|
@ -790,31 +791,52 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
}
|
||||
|
||||
private void doClose(Button closeTicketButton) {
|
||||
DisputeManager<? extends DisputeList<? extends DisputeList>> disputeManager = getDisputeManager(dispute);
|
||||
if (disputeManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isRefundAgent = disputeManager instanceof RefundManager;
|
||||
disputeResult.setLoserPublisher(isLoserPublisherCheckBox.isSelected());
|
||||
disputeResult.setCloseDate(new Date());
|
||||
dispute.setDisputeResult(disputeResult);
|
||||
dispute.setIsClosed(true);
|
||||
DisputeResult.Reason reason = disputeResult.getReason();
|
||||
String text = Res.get("disputeSummaryWindow.close.msg",
|
||||
|
||||
summaryNotesTextArea.textProperty().unbindBidirectional(disputeResult.summaryNotesProperty());
|
||||
String role = isRefundAgent ? Res.get("shared.refundAgent") : Res.get("shared.mediator");
|
||||
String agentNodeAddress = checkNotNull(disputeManager.getAgentNodeAddress(dispute)).getFullAddress();
|
||||
Contract contract = dispute.getContract();
|
||||
String currencyCode = contract.getOfferPayload().getCurrencyCode();
|
||||
String amount = formatter.formatCoinWithCode(contract.getTradeAmount());
|
||||
String textToSign = Res.get("disputeSummaryWindow.close.msg",
|
||||
DisplayUtils.formatDateTime(disputeResult.getCloseDate()),
|
||||
role,
|
||||
agentNodeAddress,
|
||||
dispute.getShortTradeId(),
|
||||
currencyCode,
|
||||
amount,
|
||||
formatter.formatCoinWithCode(disputeResult.getBuyerPayoutAmount()),
|
||||
formatter.formatCoinWithCode(disputeResult.getSellerPayoutAmount()),
|
||||
Res.get("disputeSummaryWindow.reason." + reason.name()),
|
||||
disputeResult.summaryNotesProperty().get());
|
||||
disputeResult.summaryNotesProperty().get()
|
||||
);
|
||||
|
||||
if (reason == DisputeResult.Reason.OPTION_TRADE &&
|
||||
dispute.getChatMessages().size() > 1 &&
|
||||
dispute.getChatMessages().get(1).isSystemMessage()) {
|
||||
text += "\n\n" + dispute.getChatMessages().get(1).getMessage();
|
||||
textToSign += "\n" + dispute.getChatMessages().get(1).getMessage() + "\n";
|
||||
}
|
||||
|
||||
if (dispute.getSupportType() == SupportType.MEDIATION) {
|
||||
text += Res.get("disputeSummaryWindow.close.nextStepsForMediation");
|
||||
} else if (dispute.getSupportType() == SupportType.REFUND) {
|
||||
text += Res.get("disputeSummaryWindow.close.nextStepsForRefundAgentArbitration");
|
||||
String summaryText = DisputeSummaryVerification.signAndApply(disputeManager, disputeResult, textToSign);
|
||||
|
||||
if (isRefundAgent) {
|
||||
summaryText += Res.get("disputeSummaryWindow.close.nextStepsForRefundAgentArbitration");
|
||||
} else {
|
||||
summaryText += Res.get("disputeSummaryWindow.close.nextStepsForMediation");
|
||||
}
|
||||
|
||||
checkNotNull(getDisputeManager(dispute)).sendDisputeResultMessage(disputeResult, dispute, text);
|
||||
disputeManager.sendDisputeResultMessage(disputeResult, dispute, summaryText);
|
||||
|
||||
if (peersDisputeOptional.isPresent() && !peersDisputeOptional.get().isClosed() && !DevEnv.isDevMode()) {
|
||||
UserThread.runAfter(() -> new Popup()
|
||||
|
@ -824,7 +846,6 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||
}
|
||||
|
||||
finalizeDisputeHandlerOptional.ifPresent(Runnable::run);
|
||||
|
||||
closeTicketButton.disableProperty().unbind();
|
||||
|
||||
hide();
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main.overlays.windows;
|
||||
|
||||
import bisq.desktop.main.overlays.Overlay;
|
||||
import bisq.desktop.main.support.dispute.DisputeSummaryVerification;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addMultilineLabel;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelTextArea;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelTextField;
|
||||
|
||||
@Slf4j
|
||||
public class VerifyDisputeResultSignatureWindow extends Overlay<VerifyDisputeResultSignatureWindow> {
|
||||
private TextArea textArea;
|
||||
private TextField resultTextField;
|
||||
private final MediatorManager mediatorManager;
|
||||
private final RefundAgentManager refundAgentManager;
|
||||
|
||||
public VerifyDisputeResultSignatureWindow(MediatorManager mediatorManager, RefundAgentManager refundAgentManager) {
|
||||
this.mediatorManager = mediatorManager;
|
||||
this.refundAgentManager = refundAgentManager;
|
||||
|
||||
type = Type.Attention;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (headLine == null)
|
||||
headLine = Res.get("support.sigCheck.popup.header");
|
||||
|
||||
width = 1050;
|
||||
createGridPane();
|
||||
addHeadLine();
|
||||
addContent();
|
||||
addButtons();
|
||||
|
||||
applyStyles();
|
||||
display();
|
||||
|
||||
textArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
resultTextField.setText(DisputeSummaryVerification.verifySignature(newValue,
|
||||
mediatorManager,
|
||||
refundAgentManager));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createGridPane() {
|
||||
gridPane = new GridPane();
|
||||
gridPane.setHgap(5);
|
||||
gridPane.setVgap(5);
|
||||
gridPane.setPadding(new Insets(64, 64, 64, 64));
|
||||
gridPane.setPrefWidth(width);
|
||||
|
||||
ColumnConstraints columnConstraints1 = new ColumnConstraints();
|
||||
columnConstraints1.setHalignment(HPos.RIGHT);
|
||||
columnConstraints1.setHgrow(Priority.SOMETIMES);
|
||||
gridPane.getColumnConstraints().addAll(columnConstraints1);
|
||||
}
|
||||
|
||||
private void addContent() {
|
||||
addMultilineLabel(gridPane, ++rowIndex, Res.get("support.sigCheck.popup.info"), 0, width);
|
||||
textArea = addTopLabelTextArea(gridPane, ++rowIndex, Res.get("support.sigCheck.popup.msg.label"),
|
||||
Res.get("support.sigCheck.popup.msg.prompt")).second;
|
||||
resultTextField = addTopLabelTextField(gridPane, ++rowIndex, Res.get("support.sigCheck.popup.result")).second;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main.support.dispute;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.support.dispute.DisputeList;
|
||||
import bisq.core.support.dispute.DisputeManager;
|
||||
import bisq.core.support.dispute.DisputeResult;
|
||||
import bisq.core.support.dispute.agent.DisputeAgent;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.crypto.CryptoException;
|
||||
import bisq.common.crypto.Hash;
|
||||
import bisq.common.crypto.Sig;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Slf4j
|
||||
public class DisputeSummaryVerification {
|
||||
// Must not change as it is used for splitting the text for verifying the signature of the summary message
|
||||
private static final String SEPARATOR1 = "\n-----BEGIN SIGNATURE-----\n";
|
||||
private static final String SEPARATOR2 = "\n-----END SIGNATURE-----\n";
|
||||
|
||||
public static String signAndApply(DisputeManager<? extends DisputeList<? extends DisputeList>> disputeManager,
|
||||
DisputeResult disputeResult,
|
||||
String textToSign) {
|
||||
|
||||
byte[] hash = Hash.getSha256Hash(textToSign);
|
||||
KeyPair signatureKeyPair = disputeManager.getSignatureKeyPair();
|
||||
String sigAsHex;
|
||||
try {
|
||||
byte[] signature = Sig.sign(signatureKeyPair.getPrivate(), hash);
|
||||
sigAsHex = Utilities.encodeToHex(signature);
|
||||
disputeResult.setArbitratorSignature(signature);
|
||||
} catch (CryptoException e) {
|
||||
sigAsHex = "Signing failed";
|
||||
}
|
||||
|
||||
return Res.get("disputeSummaryWindow.close.msgWithSig",
|
||||
textToSign,
|
||||
SEPARATOR1,
|
||||
sigAsHex,
|
||||
SEPARATOR2);
|
||||
}
|
||||
|
||||
public static String verifySignature(String input,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager) {
|
||||
try {
|
||||
String[] parts = input.split(SEPARATOR1);
|
||||
String textToSign = parts[0];
|
||||
String fullAddress = textToSign.split("\n")[1].split(": ")[1];
|
||||
NodeAddress nodeAddress = new NodeAddress(fullAddress);
|
||||
DisputeAgent disputeAgent = mediatorManager.getDisputeAgentByNodeAddress(nodeAddress).orElse(null);
|
||||
if (disputeAgent == null) {
|
||||
disputeAgent = refundAgentManager.getDisputeAgentByNodeAddress(nodeAddress).orElse(null);
|
||||
}
|
||||
checkNotNull(disputeAgent);
|
||||
PublicKey pubKey = disputeAgent.getPubKeyRing().getSignaturePubKey();
|
||||
|
||||
String sigString = parts[1].split(SEPARATOR2)[0];
|
||||
byte[] sig = Utilities.decodeFromHex(sigString);
|
||||
byte[] hash = Hash.getSha256Hash(textToSign);
|
||||
try {
|
||||
boolean result = Sig.verify(pubKey, hash, sig);
|
||||
if (result) {
|
||||
return Res.get("support.sigCheck.popup.success");
|
||||
} else {
|
||||
return Res.get("support.sigCheck.popup.failed");
|
||||
}
|
||||
} catch (CryptoException e) {
|
||||
return Res.get("support.sigCheck.popup.failed");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
return Res.get("support.sigCheck.popup.invalidFormat");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import bisq.desktop.main.overlays.windows.ContractWindow;
|
|||
import bisq.desktop.main.overlays.windows.DisputeSummaryWindow;
|
||||
import bisq.desktop.main.overlays.windows.SendPrivateNotificationWindow;
|
||||
import bisq.desktop.main.overlays.windows.TradeDetailsWindow;
|
||||
import bisq.desktop.main.overlays.windows.VerifyDisputeResultSignatureWindow;
|
||||
import bisq.desktop.main.shared.ChatView;
|
||||
import bisq.desktop.util.DisplayUtils;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
|
@ -42,6 +43,8 @@ import bisq.core.support.dispute.DisputeList;
|
|||
import bisq.core.support.dispute.DisputeManager;
|
||||
import bisq.core.support.dispute.DisputeResult;
|
||||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.support.messages.ChatMessage;
|
||||
import bisq.core.trade.Contract;
|
||||
import bisq.core.trade.Trade;
|
||||
|
@ -121,6 +124,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
|
|||
private final TradeDetailsWindow tradeDetailsWindow;
|
||||
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final MediatorManager mediatorManager;
|
||||
private final RefundAgentManager refundAgentManager;
|
||||
private final boolean useDevPrivilegeKeys;
|
||||
|
||||
protected TableView<Dispute> tableView;
|
||||
|
@ -136,7 +141,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
|
|||
protected FilteredList<Dispute> filteredList;
|
||||
protected InputTextField filterTextField;
|
||||
private ChangeListener<String> filterTextFieldListener;
|
||||
protected AutoTooltipButton reOpenButton, sendPrivateNotificationButton, reportButton, fullReportButton;
|
||||
protected AutoTooltipButton sigCheckButton, reOpenButton, sendPrivateNotificationButton, reportButton, fullReportButton;
|
||||
private Map<String, ListChangeListener<ChatMessage>> disputeChatMessagesListeners = new HashMap<>();
|
||||
@Nullable
|
||||
private ListChangeListener<Dispute> disputesListener; // Only set in mediation cases
|
||||
|
@ -157,6 +162,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
|
|||
ContractWindow contractWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
boolean useDevPrivilegeKeys) {
|
||||
this.disputeManager = disputeManager;
|
||||
this.keyRing = keyRing;
|
||||
|
@ -167,6 +174,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
|
|||
this.contractWindow = contractWindow;
|
||||
this.tradeDetailsWindow = tradeDetailsWindow;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.mediatorManager = mediatorManager;
|
||||
this.refundAgentManager = refundAgentManager;
|
||||
this.useDevPrivilegeKeys = useDevPrivilegeKeys;
|
||||
}
|
||||
|
||||
|
@ -222,6 +231,12 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
|
|||
showFullReport();
|
||||
});
|
||||
|
||||
sigCheckButton = new AutoTooltipButton(Res.get("support.sigCheck.button"));
|
||||
HBox.setHgrow(sigCheckButton, Priority.NEVER);
|
||||
sigCheckButton.setOnAction(e -> {
|
||||
new VerifyDisputeResultSignatureWindow(mediatorManager, refundAgentManager).show();
|
||||
});
|
||||
|
||||
Pane spacer = new Pane();
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
|
||||
|
@ -234,7 +249,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> {
|
|||
reOpenButton,
|
||||
sendPrivateNotificationButton,
|
||||
reportButton,
|
||||
fullReportButton);
|
||||
fullReportButton,
|
||||
sigCheckButton);
|
||||
VBox.setVgrow(filterBox, Priority.NEVER);
|
||||
|
||||
tableView = new TableView<>();
|
||||
|
|
|
@ -34,6 +34,8 @@ import bisq.core.support.dispute.DisputeList;
|
|||
import bisq.core.support.dispute.DisputeManager;
|
||||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.agent.MultipleHolderNameDetection;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -77,6 +79,8 @@ public abstract class DisputeAgentView extends DisputeView implements MultipleHo
|
|||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
DaoFacade daoFacade,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
boolean useDevPrivilegeKeys) {
|
||||
super(disputeManager,
|
||||
keyRing,
|
||||
|
@ -87,6 +91,8 @@ public abstract class DisputeAgentView extends DisputeView implements MultipleHo
|
|||
contractWindow,
|
||||
tradeDetailsWindow,
|
||||
accountAgeWitnessService,
|
||||
mediatorManager,
|
||||
refundAgentManager,
|
||||
useDevPrivilegeKeys);
|
||||
|
||||
multipleHolderNameDetection = new MultipleHolderNameDetection(disputeManager);
|
||||
|
|
|
@ -31,6 +31,8 @@ import bisq.core.support.dispute.Dispute;
|
|||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -55,6 +57,8 @@ public class ArbitratorView extends DisputeAgentView {
|
|||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
DaoFacade daoFacade,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(arbitrationManager,
|
||||
keyRing,
|
||||
|
@ -66,6 +70,8 @@ public class ArbitratorView extends DisputeAgentView {
|
|||
tradeDetailsWindow,
|
||||
accountAgeWitnessService,
|
||||
daoFacade,
|
||||
mediatorManager,
|
||||
refundAgentManager,
|
||||
useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ import bisq.core.support.dispute.Dispute;
|
|||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.mediation.MediationManager;
|
||||
import bisq.core.support.dispute.mediation.MediationSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -55,6 +57,8 @@ public class MediatorView extends DisputeAgentView {
|
|||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
DaoFacade daoFacade,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(mediationManager,
|
||||
keyRing,
|
||||
|
@ -66,6 +70,8 @@ public class MediatorView extends DisputeAgentView {
|
|||
tradeDetailsWindow,
|
||||
accountAgeWitnessService,
|
||||
daoFacade,
|
||||
mediatorManager,
|
||||
refundAgentManager,
|
||||
useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,10 @@ import bisq.core.dao.DaoFacade;
|
|||
import bisq.core.support.SupportType;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.RefundManager;
|
||||
import bisq.core.support.dispute.refund.RefundSession;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -55,6 +57,8 @@ public class RefundAgentView extends DisputeAgentView {
|
|||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
DaoFacade daoFacade,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(refundManager,
|
||||
keyRing,
|
||||
|
@ -66,6 +70,8 @@ public class RefundAgentView extends DisputeAgentView {
|
|||
tradeDetailsWindow,
|
||||
accountAgeWitnessService,
|
||||
daoFacade,
|
||||
mediatorManager,
|
||||
refundAgentManager,
|
||||
useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ import bisq.core.support.dispute.Dispute;
|
|||
import bisq.core.support.dispute.DisputeList;
|
||||
import bisq.core.support.dispute.DisputeManager;
|
||||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
||||
|
@ -43,9 +45,12 @@ public abstract class DisputeClientView extends DisputeView {
|
|||
ContractWindow contractWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
boolean useDevPrivilegeKeys) {
|
||||
super(DisputeManager, keyRing, tradeManager, formatter, disputeSummaryWindow, privateNotificationManager,
|
||||
contractWindow, tradeDetailsWindow, accountAgeWitnessService, useDevPrivilegeKeys);
|
||||
contractWindow, tradeDetailsWindow, accountAgeWitnessService,
|
||||
mediatorManager, refundAgentManager, useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,8 @@ import bisq.core.support.dispute.Dispute;
|
|||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationManager;
|
||||
import bisq.core.support.dispute.arbitration.ArbitrationSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -37,9 +39,8 @@ import bisq.core.util.coin.CoinFormatter;
|
|||
import bisq.common.config.Config;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@FxmlView
|
||||
public class ArbitrationClientView extends DisputeClientView {
|
||||
|
@ -53,10 +54,12 @@ public class ArbitrationClientView extends DisputeClientView {
|
|||
ContractWindow contractWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(arbitrationManager, keyRing, tradeManager, formatter, disputeSummaryWindow,
|
||||
privateNotificationManager, contractWindow, tradeDetailsWindow, accountAgeWitnessService,
|
||||
useDevPrivilegeKeys);
|
||||
mediatorManager, refundAgentManager, useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,8 @@ import bisq.core.support.dispute.Dispute;
|
|||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.mediation.MediationManager;
|
||||
import bisq.core.support.dispute.mediation.MediationSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -54,10 +56,12 @@ public class MediationClientView extends DisputeClientView {
|
|||
ContractWindow contractWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(mediationManager, keyRing, tradeManager, formatter, disputeSummaryWindow,
|
||||
privateNotificationManager, contractWindow, tradeDetailsWindow, accountAgeWitnessService,
|
||||
useDevPrivilegeKeys);
|
||||
mediatorManager, refundAgentManager, useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,8 +28,10 @@ import bisq.core.alert.PrivateNotificationManager;
|
|||
import bisq.core.support.SupportType;
|
||||
import bisq.core.support.dispute.Dispute;
|
||||
import bisq.core.support.dispute.DisputeSession;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.RefundManager;
|
||||
import bisq.core.support.dispute.refund.RefundSession;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.util.FormattingUtils;
|
||||
import bisq.core.util.coin.CoinFormatter;
|
||||
|
@ -37,9 +39,8 @@ import bisq.core.util.coin.CoinFormatter;
|
|||
import bisq.common.config.Config;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@FxmlView
|
||||
public class RefundClientView extends DisputeClientView {
|
||||
|
@ -53,10 +54,12 @@ public class RefundClientView extends DisputeClientView {
|
|||
ContractWindow contractWindow,
|
||||
TradeDetailsWindow tradeDetailsWindow,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
@Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys) {
|
||||
super(refundManager, keyRing, tradeManager, formatter, disputeSummaryWindow,
|
||||
privateNotificationManager, contractWindow, tradeDetailsWindow, accountAgeWitnessService,
|
||||
useDevPrivilegeKeys);
|
||||
mediatorManager, refundAgentManager, useDevPrivilegeKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue