retain an entered https scheme for its host when configuring a bitcoin core server
What changed, and why it matters
This commit fixes a UI behavior in Sparrow Wallet where a user-entered HTTPS scheme for a Bitcoin Core server was not being remembered. Previously, if a user typed or selected an HTTPS Bitcoin Core URL, the wallet could silently fall back to HTTP when the host or port was edited, potentially sending wallet traffic over an unencrypted connection. The patch now records that a specific host was intended to use HTTPS and keeps using HTTPS for that host unless the host is changed. This is a security-relevant correctness fix for connection configuration, not an active exploit in the code itself.
Users should upgrade to a Sparrow Wallet release containing this commit if they configure Bitcoin Core servers over HTTPS, especially when editing server settings. Review the drongo submodule bump for related protocol-handling changes. No immediate incident response is indicated, but verify that HTTPS intent is preserved in your configured Bitcoin Core server URL after editing.
Security signals we found
Protocol downgrade prevention for user-configured Bitcoin Core server connections
Retention of HTTPS intent across host/port field edits
Prevention of silent fallback from HTTPS to HTTP in server configuration UI
Connection privacy/integrity improvement for local/remote Bitcoin Core RPC traffic
Evidence from the diff
The change introduces a per-host HTTPS flag (coreHttpsHost in the desktop controller, httpsHost in the terminal dialog) that is set whenever a Bitcoin Core server URL with protocol HTTPS is loaded or entered. When the server configuration is saved or reconstructed from host/port fields, the code now selects Protocol.HTTPS if either the port is the HTTPS default port OR the host matches the previously recorded HTTPS host. This prevents unintended downgrade to HTTP when editing host/port fields after an HTTPS URL was entered. The terminal ServerUrlDialog base class signature for setProtocol is updated to include the host, and PrivateElectrumDialog is updated accordingly. A drongo submodule bump is included but not analyzed in the diff.
Changed components
Sparrow Wallet desktop settings UI (ServerSettingsController.java)Sparrow Wallet terminal/TUI Bitcoin Core dialog (BitcoinCoreDialog.java)Sparrow Wallet terminal/TUI server URL dialog base class (ServerUrlDialog.java)Sparrow Wallet terminal/TUI Private Electrum dialog (PrivateElectrumDialog.java)drongo submodule (commit reference changed, contents not shown)Inspect captured patch +31 / −10
### drongo
@@ -1 +1 @@
-Subproject commit 080cf3f7cf74133ba68b369065d0f2e7ea4337da
+Subproject commit 59f43e3aa3adeafeed2f1792054b4d2f65014434
### src/main/java/com/sparrowwallet/sparrow/settings/ServerSettingsController.java
@@ -177,6 +177,8 @@ public class ServerSettingsController extends SettingsDetailController {
private boolean coreServerWarningShown;
+ private String coreHttpsHost;
+
@Override
public void initializeView(Config config) {
EventManager.get().register(this);
@@ -320,6 +322,7 @@ public void initializeView(Config config) {
}
} else if(newValue.getHostAndPort() != null) {
HostAndPort hostAndPort = newValue.getHostAndPort();
+ setCoreProtocol(newValue.getProtocol(), hostAndPort.getHost());
corePort.setText(hostAndPort.hasPort() ? Integer.toString(hostAndPort.getPort()) : "");
if(newValue.getAlias() != null) {
coreHost.setText(newValue.getAlias());
@@ -459,6 +462,7 @@ public void initializeView(Config config) {
Server coreServer = config.getCoreServer();
if(coreServer != null) {
+ setCoreProtocol(coreServer.getProtocol(), coreServer.getHost());
HostAndPort hostAndPort = coreServer.getHostAndPort();
Server server = config.getRecentCoreServers().stream().filter(coreServer::equals).findFirst().orElse(null);
if(server != null) {
@@ -788,6 +792,7 @@ private ChangeListener<String> getBitcoinCoreListener(Config config) {
if(Protocol.getProtocol(oldValue) == null) {
HostAndPort hostAndPort = protocol.getServerHostAndPort(newValue);
if(!hostAndPort.getHost().isEmpty()) {
+ setCoreProtocol(protocol, hostAndPort.getHost());
coreHost.setText(hostAndPort.getHost());
corePort.setText(hostAndPort.hasPort() ? String.valueOf(hostAndPort.getPort()) : "");
}
@@ -810,15 +815,21 @@ private void setCoreServerInConfig(Config config) {
String hostAsString = getHost(coreHost.getText());
Integer portAsInteger = getPort(corePort.getText());
if(hostAsString != null && !hostAsString.isEmpty() && portAsInteger != null && isValidPort(portAsInteger)) {
- Protocol protocol = portAsInteger == Protocol.HTTPS.getDefaultPort() ? Protocol.HTTPS : Protocol.HTTP;
+ Protocol protocol = portAsInteger == Protocol.HTTPS.getDefaultPort() || hostAsString.equalsIgnoreCase(coreHttpsHost) ? Protocol.HTTPS : Protocol.HTTP;
config.setCoreServer(new Server(protocol.toUrlString(hostAsString, portAsInteger)));
} else if(hostAsString != null && !hostAsString.isEmpty()) {
- config.setCoreServer(new Server(Protocol.HTTP.toUrlString(hostAsString)));
+ Protocol protocol = hostAsString.equalsIgnoreCase(coreHttpsHost) ? Protocol.HTTPS : Protocol.HTTP;
+ config.setCoreServer(new Server(protocol.toUrlString(hostAsString)));
} else {
config.setCoreServer(null);
}
}
+ //An entered https is retained for the host it was entered on only, so that editing the host to another server returns to http as a typed or scanned host without a scheme does
+ private void setCoreProtocol(Protocol protocol, String host) {
+ coreHttpsHost = protocol == Protocol.HTTPS ? host : null;
+ }
+
private void showRemoteCoreServerWarning(Config config) {
Server coreServer = config.getCoreServer();
if(!coreServerWarningShown && config.getServerType() == ServerType.BITCOIN_CORE && isRemoteNode(coreServer)) {
### src/main/java/com/sparrowwallet/sparrow/terminal/settings/BitcoinCoreDialog.java
@@ -22,6 +22,8 @@ public class BitcoinCoreDialog extends ServerUrlDialog {
private final TextBox user;
private final TextBox pass;
+ private String httpsHost;
+
public BitcoinCoreDialog() {
super("Bitcoin Core");
@@ -31,7 +33,9 @@ public BitcoinCoreDialog() {
if(Config.get().getCoreServer() == null) {
Config.get().setCoreServer(new Server("http://127.0.0.1:" + Network.get().getDefaultPort()));
}
- addUrlComponents(mainPanel, Config.get().getRecentCoreServers(), Config.get().getCoreServer());
+ Server coreServer = Config.get().getCoreServer();
+ setProtocol(coreServer.getProtocol(), coreServer.getHost());
+ addUrlComponents(mainPanel, Config.get().getRecentCoreServers(), coreServer);
addLine(mainPanel);
mainPanel.addComponent(new Label("Authentication"));
@@ -127,11 +131,13 @@ protected void setServerAlias(Server server) {
protected Protocol getProtocol() {
Integer portAsInteger = getServerPort();
- return portAsInteger != null && portAsInteger == Protocol.HTTPS.getDefaultPort() ? Protocol.HTTPS : Protocol.HTTP;
+ boolean https = (portAsInteger != null && portAsInteger == Protocol.HTTPS.getDefaultPort()) || (httpsHost != null && httpsHost.equalsIgnoreCase(getServerHost()));
+ return https ? Protocol.HTTPS : Protocol.HTTP;
}
- protected void setProtocol(Protocol protocol) {
- //empty
+ //An https is retained for the host it was entered on only, so that editing the URL to another server returns to http
+ protected void setProtocol(Protocol protocol, String host) {
+ httpsHost = protocol == Protocol.HTTPS ? host : null;
}
private void setCoreAuth() {
### src/main/java/com/sparrowwallet/sparrow/terminal/settings/PrivateElectrumDialog.java
@@ -98,7 +98,7 @@ protected Protocol getProtocol() {
return (useSsl.getSelectedIndex() == 0 ? Protocol.SSL : Protocol.TCP);
}
- protected void setProtocol(Protocol protocol) {
+ protected void setProtocol(Protocol protocol, String host) {
useSsl.setSelectedIndex(protocol == Protocol.SSL ? 0 : 1);
}
}
### src/main/java/com/sparrowwallet/sparrow/terminal/settings/ServerUrlDialog.java
@@ -53,9 +53,9 @@ protected void addUrlComponents(Panel mainPanel, List<Server> recentServers, Ser
Optional<Server> optServer = recentServers.stream().filter(server -> server.equals(host.getSelectedItem().getServer())).findFirst();
if(optServer.isPresent()) {
Server server = optServer.get();
+ setProtocol(server.getProtocol(), server.getHost());
port.setText(server.getHostAndPort().hasPort() ? Integer.toString(server.getHostAndPort().getPort()) : "");
alias.setText(server.getAlias() == null ? "" : server.getAlias());
- setProtocol(server.getProtocol());
}
setServerConfig();
});
@@ -89,7 +89,7 @@ protected void onTest() {
protected abstract Protocol getProtocol();
- protected abstract void setProtocol(Protocol protocol);
+ protected abstract void setProtocol(Protocol protocol, String host);
protected Server getCurrentServer() {
String hostAsString = getHost(host.getText());
@@ -103,6 +103,10 @@ protected Server getCurrentServer() {
return null;
}
+ protected String getServerHost() {
+ return getHost(host.getText());
+ }
+
protected Integer getServerPort() {
return getPort(port.getText());
}Why this scored 36/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.