RDP rework

This commit is contained in:
crschnick
2026-06-26 08:38:22 +00:00
parent 036b5f898a
commit 9fcfb10a08
11 changed files with 64 additions and 46 deletions
@@ -54,7 +54,7 @@ public class CustomRdpClient implements ExternalApplicationType, ExternalRdpClie
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return false;
}
@@ -56,7 +56,7 @@ public class DevolutionsRdpClient implements ExternalApplicationType.WindowsType
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return false;
}
@@ -87,7 +87,7 @@ public interface ExternalRdpClient extends PrefsValue {
void launch(RdpLaunchConfig configuration) throws Exception;
boolean supportsPasswordPassing(RdpLaunchConfig config);
boolean supportsPasswordPassing();
String getWebsite();
@@ -13,8 +13,6 @@ import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.util.Map;
@JsonTypeName("freeRdp")
@Value
@Jacksonized
@@ -33,7 +31,15 @@ public class FreeRdpClient implements ExternalRdpClient {
var v3 = CommandSupport.isInLocalPath("xfreerdp3");
if (!v3) {
var v2 = CommandSupport.isInLocalPath("xfreerdp");
if (!v2 && OsType.ofLocal() == OsType.LINUX) {
// macOS uses xfreerdp3 by default
if (OsType.ofLocal() == OsType.MACOS && v2) {
exec = CommandBuilder.of().add("xfreerdp");
v3 = true;
} else if (v2) {
exec = CommandBuilder.of().add("xfreerdp");
v3 = false;
} else if (OsType.ofLocal() == OsType.LINUX) {
var flatpak = FlatpakCache.getApp("com.freerdp.FreeRDP");
if (flatpak.isPresent()) {
exec = FlatpakCache.getRunCommand("com.freerdp.FreeRDP");
@@ -42,10 +48,7 @@ public class FreeRdpClient implements ExternalRdpClient {
return null;
}
} else {
CommandSupport.isInPathOrThrow(LocalShell.getShell(), "xfreerdp");
exec = CommandBuilder.of().add("xfreerdp");
// macOS uses xfreerdp3 by default
v3 = true;
return null;
}
} else {
exec = CommandBuilder.of().add("xfreerdp3");
@@ -55,13 +58,16 @@ public class FreeRdpClient implements ExternalRdpClient {
private Executable getWaylandCommandBase() throws Exception {
CommandBuilder exec;
var v3 = CommandSupport.isInLocalPath("wlfreerdp3");
var v3 = CommandSupport.isInLocalPath("sdl-freerdp3") || CommandSupport.isInLocalPath("wlfreerdp3");
if (!v3) {
var v2 = CommandSupport.isInLocalPath("wlfreerdp");
if (!v2 && OsType.ofLocal() == OsType.LINUX) {
if (v2) {
exec = CommandBuilder.of().add("wlfreerdp");
v3 = false;
} else if (OsType.ofLocal() == OsType.LINUX) {
var flatpak = FlatpakCache.getApp("com.freerdp.FreeRDP");
if (flatpak.isPresent()) {
exec = FlatpakCache.getRunCommand("com.freerdp.FreeRDP", "sdl-freerdp");
exec = FlatpakCache.getRunCommand("com.freerdp.FreeRDP", "sdl-freerdp3");
v3 = true;
} else {
return null;
@@ -71,7 +77,7 @@ public class FreeRdpClient implements ExternalRdpClient {
return null;
}
} else {
exec = CommandBuilder.of().add("wlfreerdp3");
exec = CommandSupport.isInLocalPath("sdl-freerdp3") ? CommandBuilder.of().add("sdl-freerdp3") : CommandBuilder.of().add("wlfreerdp3");
}
return new Executable(exec, v3);
}
@@ -85,7 +91,7 @@ public class FreeRdpClient implements ExternalRdpClient {
}
if (exec == null) {
throw ErrorEventFactory.expected(new IllegalStateException("Unable to find a FreeRDP v2 or v3 installation"));
throw ErrorEventFactory.expected(new IllegalStateException("Unable to find a FreeRDP executable for v2 or v3 in the PATH or as a flatpak"));
}
var file = writeRdpConfigFile(configuration.getTitle(), configuration.getConfig());
@@ -100,6 +106,16 @@ public class FreeRdpClient implements ExternalRdpClient {
.add("-themes")
.add("/size:100%");
b.add(argument("/v", configuration.getHost()));
if (configuration.getUsername() != null) {
b.add(argument("/u", configuration.getUsernameWithoutDomain()));
}
if (configuration.getDomain().isPresent()) {
b.add(argument("/d", configuration.getDomain().get()));
}
if (configuration.getPassword() != null) {
b.add(argument("/p", configuration.getPassword().getSecretValue()));
}
@@ -110,7 +126,10 @@ public class FreeRdpClient implements ExternalRdpClient {
// Horrible quoting rules: https://github.com/FreeRDP/FreeRDP/issues/11396
String s = "g:" + gateway.getHost();
if (gateway.getUsername() != null) {
s += "," + gatewayArgument("u", gateway.getUsername());
s += "," + gatewayArgument("u", gateway.getUsernameWithoutDomain());
}
if (gateway.getDomain().isPresent()) {
s += "," + gatewayArgument("d", gateway.getDomain().get());
}
if (gateway.getPassword() != null) {
s += "," + gatewayArgument("p", gateway.getPassword().getSecretValue());
@@ -146,7 +165,7 @@ public class FreeRdpClient implements ExternalRdpClient {
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return true;
}
@@ -34,7 +34,7 @@ public class KrdcRdpClient implements ExternalApplicationType.LinuxApplication,
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return false;
}
@@ -1,19 +1,13 @@
package io.xpipe.app.rdp;
import com.sun.jna.LastErrorException;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import io.xpipe.app.comp.base.ModalButton;
import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppDisplayScale;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.platform.ClipboardHelper;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.process.LocalShell;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.*;
@@ -27,10 +21,7 @@ import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import org.apache.commons.io.FileUtils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
@@ -231,7 +222,7 @@ public class MstscRdpClient implements ExternalApplicationType.PathApplication,
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return true;
}
@@ -6,6 +6,7 @@ import io.xpipe.app.util.SecretValue;
import lombok.Value;
import java.util.Optional;
import java.util.UUID;
@Value
@@ -15,4 +16,18 @@ public class RdpLaunchConfigGateway {
String username;
SecretValue password;
boolean reused;
public Optional<String> getDomain() {
var domain = username.contains("\\") ? username.split("\\\\")[0] : null;
return Optional.ofNullable(domain);
}
public String getUsernameWithoutDomain() {
if (username.contains("\\")) {
return username.split("\\\\")[1];
} else {
return username;
}
}
}
@@ -9,8 +9,6 @@ import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.util.*;
@JsonTypeName("remmina")
@Value
@Jacksonized
@@ -34,7 +32,7 @@ public class RemminaRdpClient implements ExternalApplicationType.LinuxApplicatio
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return true;
}
@@ -36,7 +36,7 @@ public class RemoteDesktopAppRdpClient implements ExternalApplicationType.MacApp
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return false;
}
@@ -35,7 +35,7 @@ public class WindowsAppRdpClient implements ExternalApplicationType.MacApplicati
}
@Override
public boolean supportsPasswordPassing(RdpLaunchConfig config) {
public boolean supportsPasswordPassing() {
return false;
}
@@ -9,6 +9,7 @@ import io.xpipe.app.vnc.VncLaunchConfig;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;
@@ -60,23 +61,17 @@ public class RemminaHelper {
var name = OsFileSystem.ofLocal().makeFileSystemCompatible(configuration.getTitle());
var file = AppLocalTemp.getLocalTempDataDirectory("remmina").resolve("xpipe-" + name + ".remmina");
var gateway = "";
var gateway = new ArrayList<String>();
if (configuration.getGateway() != null) {
gateway += "gateway_server=" + configuration.getGateway().getHost();
gateway.add("gateway_server=" + configuration.getGateway().getHost());
if (configuration.getGateway().getUsername() != null) {
var gatewayUser = configuration.getGateway().getUsername();
var gatewayDomain = gatewayUser.contains("\\") ? gatewayUser.split("\\\\")[0] : null;
if (gatewayDomain != null) {
gatewayUser = gatewayUser.split("\\\\")[1];
}
gateway += "gateway_username=" + gatewayUser;
if (gatewayDomain != null) {
gateway += "gateway_domain=" + gatewayDomain;
gateway.add("gateway_username=" + configuration.getGateway().getUsernameWithoutDomain());
if (configuration.getGateway().getDomain().isPresent()) {
gateway.add("gateway_domain=" + configuration.getGateway().getDomain().get());
}
}
if (configuration.getGateway().getPassword() != null) {
gateway += "gateway_password=" + RemminaHelper.encryptPassword(configuration.getGateway().getPassword());
gateway.add("gateway_password=" + RemminaHelper.encryptPassword(configuration.getGateway().getPassword()).orElse(""));
}
}
@@ -102,7 +97,7 @@ public class RemminaHelper {
w,
h,
maximize,
!gateway.isEmpty() ? "\n" + gateway : "");
!gateway.isEmpty() ? "\n" + String.join("\n", gateway) : "");
Files.createDirectories(file.getParent());
Files.writeString(file, string);
return file;