Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backup, restore and create a new onion address via GUI #3044

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions core/src/main/java/bisq/core/trade/TradeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -265,6 +267,7 @@ public void onUpdatedDataReceived() {
}

public void shutDown() {
reportActiveHiddenServices();
}

private void initPendingTrades() {
Expand Down Expand Up @@ -584,6 +587,21 @@ public void removePreparedTrade(Trade trade) {

private void removeTrade(Trade trade) {
tradableList.remove(trade);

reportActiveHiddenServices();
}

/**
* Collect all node addresses (hidden services) we still need for active offers/trades
* and report them to the P2P Service. The P2PService will report to the NetworkNode
* for cleaning up unnecessary hidden services.
*/
private void reportActiveHiddenServices() {
Set<NodeAddress> result = new HashSet<>();
result.addAll(openOfferManager.getObservableList().stream().map(openOffer -> openOffer.getOffer().getOfferPayload().getOwnerNodeAddress()).collect(Collectors.toSet()));
result.addAll(getTradableList().stream().map(Trade::getContract).filter(Objects::nonNull).map(contract -> contract.getMyNodeAddress(keyRing.getPubKeyRing())).collect(Collectors.toSet()));

p2PService.reportRequiredHiddenServices(result);
}


Expand Down
9 changes: 9 additions & 0 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,15 @@ setting.preferences.dao.fullNodeInfo.cancel=No, I stick with lite node mode
settings.net.btcHeader=Bitcoin network
settings.net.p2pHeader=Bisq network
settings.net.onionAddressLabel=My onion address
settings.net.renewAddressButton=Create new address
settings.net.renewAddress=Please be aware that you will loose your reputation when you create and use a new onion address. Furthermore, you need to restart the application to set your new onion address active.\n\nProceed?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
settings.net.renewAddress=Please be aware that you will loose your reputation when you create and use a new onion address. Furthermore, you need to restart the application to set your new onion address active.\n\nProceed?
settings.net.renewAddress=Please be aware that you will lose your reputation when you create and use a new onion address. Furthermore, you need to restart the application to set your new onion address active.\n\nProceed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should emphasize the significance of this action. Although it wont remove the old address immediately if there are open offers/trades, they will not be able to back up the old address after creating a new address. So perhaps highly recommend that they backup prior to creating a new address if there are open trades/offers or perhaps even if there are closed trades (just in case).

settings.net.exportAddressButton=Backup address
settings.net.exportAddressFileDialog=Select the backup file
settings.net.exportAddressFileEnding=Bisq Onion Address Backup (*.bisq)
settings.net.importAddressButton=Restore address
settings.net.importAddressFileDialog=Select the backup file
settings.net.importAddress=Please be aware that you will loose your reputation when you restore a previous onion address (but restore your reputation connected to the restored onion address). Furthermore, you need to restart the application to set your new onion address active.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
settings.net.importAddress=Please be aware that you will loose your reputation when you restore a previous onion address (but restore your reputation connected to the restored onion address). Furthermore, you need to restart the application to set your new onion address active.
settings.net.importAddress=Please be aware that you will lose your reputation when you restore a previous onion address (but restore your reputation connected to the restored onion address). Furthermore, you need to restart the application to set your new onion address active.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned with renew address, perhaps we should emphasize the significance of this action as well.

settings.net.importAddressError=Bisq could not import the backup file you specified. Be sure you chose a valid file and the file exists. If you are sure everything has been correct, please proceed below.
settings.net.btcNodesLabel=Use custom Bitcoin Core nodes
settings.net.bitcoinPeersLabel=Connected peers
settings.net.useTorForBtcJLabel=Use Tor for Bitcoin network
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/resources/i18n/displayStrings_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,15 @@ setting.preferences.dao.fullNodeInfo.cancel=Nein, ich möchte weiterhin den Lite
settings.net.btcHeader=Bitcoin-Netzwerk
settings.net.p2pHeader=Bisq-Netzwerk
settings.net.onionAddressLabel=Meine Onion-Adresse
settings.net.renewAddressButton=Neue Adresse verwenden
settings.net.renewAddress=Ihre Reputation ist an die aktuelle Onion-Adresse gebunden. Wenn Sie die aktuelle Adresse ersetzen, verlieren Sie auch die damit verbundene Reputation. Die neue Adresse wird nach einem Neustart der Software aktiv.\n\nWollen Sie den Adresswechsel anwenden und die Software neu starten?
settings.net.exportAddressButton=Adresse sichern
settings.net.exportAddressFileDialog=Sicherungsdatei auswählen
settings.net.exportAddressFileEnding=Bisq Onion Adresse Sicherungsdatei (*.bisq)
settings.net.importAddressButton=Adresse wiederherstellen
settings.net.importAddressFileDialog=Sicherungsdatei auswählen
settings.net.importAddress=Ihre Reputation ist an die aktuelle Onion-Adresse gebunden. Wenn Sie die aktuelle Adresse ersetzen, verlieren Sie auch die damit verbundene Reputation. Dafür wird mit der Wiederherstellung einer alten Adresse deren Reputation wieder aktiv. Die neue Adresse wird nach einem Neustart der Software aktiv.
settings.net.importAddressError=Wiederherstellen der Sicherung war nicht erfolgreich. Stellen Sie sicher, dass Sie die korrekte Sicherungsdatei ausgewählt haben und diese auch existiert und versuchen Sie es erneut. Sollte das Problem wiederholt auftreten, bitte beachten Sie die nachfolgenden Hinweise.
settings.net.btcNodesLabel=Spezifische Bitcoin-Core-Knoten verwenden
settings.net.bitcoinPeersLabel=Verbundene Peers
settings.net.useTorForBtcJLabel=Tor für das Bitcoin-Netzwerk verwenden
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,19 @@
</GridPane.margin>
</TitledGroupBg>

<BisqTextField fx:id="onionAddress" GridPane.rowIndex="5"
editable="false" focusTraversable="false" labelFloat="true">
<HBox spacing="10" GridPane.rowIndex="5">
<GridPane.margin>
<Insets top="60.0"/>
</GridPane.margin>
</BisqTextField>
<BisqTextField fx:id="onionAddress" HBox.hgrow="ALWAYS"
editable="false" focusTraversable="false" labelFloat="true"/>

<AutoTooltipButton fx:id="renewIdButton"/>

<AutoTooltipButton fx:id="exportIdButton"/>

<AutoTooltipButton fx:id="importIdButton"/>
</HBox>

<VBox GridPane.rowIndex="6" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES">
<AutoTooltipLabel fx:id="p2PPeersLabel" styleClass="small-text"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@

import javafx.fxml.FXML;

import javafx.stage.FileChooser;

import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
Expand All @@ -70,6 +72,9 @@
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;

import java.io.File;
import java.io.IOException;

import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -103,7 +108,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
@FXML
Label reSyncSPVChainLabel;
@FXML
AutoTooltipButton reSyncSPVChainButton, openTorSettingsButton;
AutoTooltipButton reSyncSPVChainButton, renewIdButton, exportIdButton, importIdButton, openTorSettingsButton;

private final Preferences preferences;
private final BtcNodes btcNodes;
Expand Down Expand Up @@ -177,6 +182,9 @@ public void initialize() {
usePublicNodesRadio.setText(Res.get("settings.net.usePublicNodesRadio"));
reSyncSPVChainLabel.setText(Res.get("settings.net.reSyncSPVChainLabel"));
reSyncSPVChainButton.updateText(Res.get("settings.net.reSyncSPVChainButton"));
renewIdButton.updateText(Res.get("settings.net.renewAddressButton"));
exportIdButton.updateText(Res.get("settings.net.exportAddressButton"));
importIdButton.updateText(Res.get("settings.net.importAddressButton"));
p2PPeersLabel.setText(Res.get("settings.net.p2PPeersLabel"));
onionAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn")));
onionAddressColumn.getStyleClass().add("first-column");
Expand Down Expand Up @@ -288,6 +296,47 @@ public void activate() {

reSyncSPVChainButton.setOnAction(event -> GUIUtil.reSyncSPVChain(preferences));

renewIdButton.setOnAction(event -> {
new Popup().information(Res.get("settings.net.renewAddress"))
.actionButtonText(Res.get("shared.applyAndShutDown"))
.onAction(() -> {
p2PService.renewHiddenService();
UserThread.runAfter(BisqApp.getShutDownHandler()::run, 500, TimeUnit.MILLISECONDS);
})
.closeButtonText(Res.get("shared.cancel"))
.show();
});

exportIdButton.setOnAction(event -> {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(Res.get("settings.net.exportAddressFileDialog"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(Res.get("settings.net.exportAddressFileEnding"), "*.bisq"));
File file = fileChooser.showSaveDialog(root.getScene().getWindow());
if (file != null)
p2PService.exportHiddenService(file);
});

importIdButton.setOnAction(event -> {
new Popup().information(Res.get("settings.net.importAddress"))
.actionButtonText(Res.get("settings.net.importAddressFileDialog"))
.onAction(() -> {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(Res.get("settings.net.importAddressFileDialog"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(Res.get("settings.net.exportAddressFileEnding"), "*.bisq"));
File file = fileChooser.showOpenDialog(root.getScene().getWindow());
if (file == null)
return;
try {
p2PService.importHiddenService(file);
UserThread.runAfter(BisqApp.getShutDownHandler()::run, 500, TimeUnit.MILLISECONDS);
} catch (IOException e) {
new Popup().error(Res.get("settings.net.importAddressError")).show();
}
})
.closeButtonText(Res.get("shared.cancel"))
.show();
});

bitcoinPeersSubscription = EasyBind.subscribe(walletsSetup.connectedPeersProperty(),
connectedPeers -> updateBitcoinPeersTable());

Expand Down Expand Up @@ -330,6 +379,10 @@ public void deactivate() {

useTorForBtcJCheckBox.setOnAction(null);

renewIdButton.setOnAction(null);
freimair marked this conversation as resolved.
Show resolved Hide resolved
exportIdButton.setOnAction(null);
importIdButton.setOnAction(null);

if (nodeAddressSubscription != null)
nodeAddressSubscription.unsubscribe();

Expand Down
4 changes: 2 additions & 2 deletions monitor/src/main/java/bisq/monitor/AvailableTor.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public Tor getTor() {
}

@Override
public String getHiddenServiceDirectory() {
return hiddenServiceDirectory;
public File getHiddenServiceBaseDirectory() {
return new File(hiddenServiceDirectory);
}

}
47 changes: 42 additions & 5 deletions p2p/src/main/java/bisq/network/p2p/P2PService.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@

import java.security.PublicKey;

import java.io.File;
import java.io.IOException;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -204,6 +207,10 @@ public void onAllServicesInitialized() {
}
}

public void renewHiddenService() {
networkNode.renewHiddenService();
}

public void shutDown(Runnable shutDownCompleteHandler) {
if (!shutDownInProgress) {
shutDownInProgress = true;
Expand Down Expand Up @@ -903,13 +910,43 @@ public KeyRing getKeyRing() {
///////////////////////////////////////////////////////////////////////////////////////////

private boolean verifyAddressPrefixHash(PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage) {
if (networkNode.getNodeAddress() != null) {
byte[] blurredAddressHash = networkNode.getNodeAddress().getAddressPrefixHash();
return blurredAddressHash != null &&
Arrays.equals(blurredAddressHash, prefixedSealedAndSignedMessage.getAddressPrefixHash());
} else {
if (networkNode.getNodeAddress() == null) {
log.debug("myOnionAddress is null at verifyAddressPrefixHash. That is expected at startup.");
return false;
}

Set<NodeAddress> activeNodeAddresses = networkNode.getActiveNodeAddresses();

return activeNodeAddresses.stream().map(nodeAddress -> Arrays.equals(nodeAddress.getAddressPrefixHash(), prefixedSealedAndSignedMessage.getAddressPrefixHash())).reduce(false, (a, b) -> a || b);
}

/**
* Reporting hidden services that are still needed has the following background:
* <p><ul>
* <li> when we only report a hidden service if it is no longer used, we have that
* one chance of shutting it down. If for whatever reason we fail on doing so, we
* are stuck with this particular HS forever (without additional code)
* <li> we do not need to find our exact node address by complex queries to the trade
* and offers, we just add all node address to the list. If we report
* a HS that is not ours, well, then we cannot retain it as we do not have it
* and that is it. No harm done. On the other hand, if we select the wrong HS as
* being ours, we probably remove a HS that is still in use.
* <li> the code is much more compact and therefore, less error prone
* <li> by reporting the stuff we need to keep, our code is more robust in terms of
* missing one
* </ul></p>
*
* @param nodeAddressList the list of node addresses we need to retain
*/
public void reportRequiredHiddenServices(Set<NodeAddress> nodeAddressList) {
networkNode.clearHiddenServices(nodeAddressList);
}

public void exportHiddenService(File file) {
networkNode.exportHiddenService(file);
}

public void importHiddenService(File file) throws IOException {
networkNode.importHiddenService(file);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import java.net.ServerSocket;
import java.net.Socket;

import java.io.File;
import java.io.IOException;

import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
Expand Down Expand Up @@ -84,9 +86,29 @@ public void start(@Nullable SetupListener setupListener) {
}, simulateTorDelayHiddenService, TimeUnit.MILLISECONDS);
}

@Override
public File renewHiddenService() {
return null;
}

// Called from NetworkNode thread
@Override
protected Socket createSocket(NodeAddress peerNodeAddress) throws IOException {
return new Socket(peerNodeAddress.getHostName(), peerNodeAddress.getPort());
}

@Override
public void clearHiddenServices(Set<NodeAddress> nodeAddressList) {

}

@Override
public void exportHiddenService(File file) {

}

@Override
public void importHiddenService(File source) {

}
}
24 changes: 24 additions & 0 deletions p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.net.ServerSocket;
import java.net.Socket;

import java.io.File;
import java.io.IOException;

import java.util.HashSet;
Expand Down Expand Up @@ -231,6 +232,20 @@ public void onFailure(@NotNull Throwable throwable) {
}
}

public abstract File renewHiddenService();

/**
* Gets rid of all hidden services except those given in the retain
* parameter.
*
* @param retain contains the hidden services that are still in use
*/
public abstract void clearHiddenServices(Set<NodeAddress> retain);

public abstract void exportHiddenService(File target);

public abstract void importHiddenService(File source) throws IOException;

@Nullable
private InboundConnection getInboundConnection(@NotNull NodeAddress peersNodeAddress) {
Optional<InboundConnection> inboundConnectionOptional = lookupInBoundConnection(peersNodeAddress);
Expand Down Expand Up @@ -468,4 +483,13 @@ private void printInboundConnections() {
public NodeAddress getNodeAddress() {
return nodeAddressProperty.get();
}

/**
* Returns a collection of node addresses which have been used in the past and are
* kept active until no longer needed.
* @return
*/
public Set<NodeAddress> getActiveNodeAddresses() {
return Set.of(getNodeAddress());
}
}
6 changes: 0 additions & 6 deletions p2p/src/main/java/bisq/network/p2p/network/NewTor.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,4 @@ public Tor getTor() throws IOException, TorCtlException {

return result;
}

@Override
public String getHiddenServiceDirectory() {
return "";
}

}
6 changes: 0 additions & 6 deletions p2p/src/main/java/bisq/network/p2p/network/RunningTor.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,4 @@ else if (cookieFile.exists())

return result;
}

@Override
public String getHiddenServiceDirectory() {
return new File(torDir, HIDDEN_SERVICE_DIRECTORY).getAbsolutePath();
}

}
Loading