diff --git a/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java index 4c61945aa..230b38ce3 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/AppBaseMode.java @@ -25,6 +25,7 @@ import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.WorkspaceManager; import io.xpipe.app.process.LocalShell; +import io.xpipe.app.rdp.MicrosoftRdpClient; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorageMigratedDialog; import io.xpipe.app.storage.DataStorageSyncHandler; @@ -220,6 +221,7 @@ public class AppBaseMode extends AppOperationMode { AppMcpServer.reset(); WorkspaceManager.reset(); RemoteDesktopWindow.reset(); + MicrosoftRdpClient.reset(); AppPrefs.reset(); DataStorage.reset(); DataStorageSyncHandler.getInstance().reset(); diff --git a/app/src/main/java/io/xpipe/app/rdp/MicrosoftRdpClient.java b/app/src/main/java/io/xpipe/app/rdp/MicrosoftRdpClient.java index 8aefebbe4..b5abfcce3 100644 --- a/app/src/main/java/io/xpipe/app/rdp/MicrosoftRdpClient.java +++ b/app/src/main/java/io/xpipe/app/rdp/MicrosoftRdpClient.java @@ -10,6 +10,7 @@ import io.xpipe.app.platform.OptionsBuilder; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.ExternalApplicationType; import io.xpipe.app.process.LocalShell; +import io.xpipe.app.secret.InPlaceSecretValue; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.*; @@ -25,9 +26,7 @@ import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; import java.time.Duration; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @SuperBuilder(toBuilder = true) @@ -148,6 +147,16 @@ public abstract class MicrosoftRdpClient implements ExternalApplicationType.Inst private static final int CRED_TYPE_GENERIC = 1; private static final int CRED_TYPE_DOMAIN_PASSWORD = 2; private static final int CRED_PERSIST_SESSION = 1; + + private static final Set storedCredentials = new HashSet(); + + public static void reset() { + synchronized (storedCredentials) { + for (String s : storedCredentials) { + AuthModuleProvider.get().deleteWindowsCredential(s, CRED_PERSIST_SESSION); + } + } + } @Override public void launch(RdpLaunchConfig configuration) throws Exception { @@ -185,25 +194,33 @@ public abstract class MicrosoftRdpClient implements ExternalApplicationType.Inst disableSignatureWarning(configuration); - if (configuration.getPassword() != null) { - AuthModuleProvider.get() - .setWindowsCredential( - "TERMSRV/" + configuration.getHost(), - CRED_TYPE_GENERIC, - CRED_PERSIST_SESSION, - configuration.getUsername(), - configuration.getPassword()); - } + synchronized (storedCredentials) { + if (configuration.getPassword() != null) { + String target = "TERMSRV/" + configuration.getHost(); - var gateway = configuration.getGateway(); - if (gateway != null && gateway.getPassword() != null) { - AuthModuleProvider.get() - .setWindowsCredential( - gateway.getHost(), - CRED_TYPE_GENERIC, - CRED_PERSIST_SESSION, - gateway.getUsername(), - gateway.getPassword()); + var existing = AuthModuleProvider.get().getWindowsCredential(target, CRED_TYPE_GENERIC); + if (existing.isPresent()) { + AuthModuleProvider.get().setWindowsCredential(target, CRED_TYPE_GENERIC, CRED_PERSIST_SESSION, configuration.getUsername(), + configuration.getPassword()); + storedCredentials.add(target); + } + + GlobalTimer.delay(() -> { + AuthModuleProvider.get().deleteWindowsCredential(target, CRED_PERSIST_SESSION); + }, Duration.ofSeconds(120)); + } + + var gateway = configuration.getGateway(); + if (gateway != null && gateway.getPassword() != null) { + String target = gateway.getHost(); + AuthModuleProvider.get().setWindowsCredential(target, CRED_TYPE_GENERIC, CRED_PERSIST_SESSION, gateway.getUsername(), + gateway.getPassword()); + storedCredentials.add(target); + + GlobalTimer.delay(() -> { + AuthModuleProvider.get().deleteWindowsCredential(target, CRED_PERSIST_SESSION); + }, Duration.ofSeconds(120)); + } } var file = writeRdpConfigFile(configuration.getTitle(), adaptedRdpConfig); @@ -267,6 +284,16 @@ public abstract class MicrosoftRdpClient implements ExternalApplicationType.Inst private RdpConfig getAdaptedConfig(RdpLaunchConfig configuration) { var input = configuration.getConfig(); var pass = configuration.getPassword(); + + // Use existing pw if possible and needed + if (pass == null) { + String target = "TERMSRV/" + configuration.getHost(); + var existing = AuthModuleProvider.get().getWindowsCredential(target, CRED_TYPE_GENERIC); + if (existing.isPresent()) { + pass = InPlaceSecretValue.of(existing.get().getPassword()); + } + } + var adapted = input.overlay(Map.of( "prompt for credentials", new RdpConfig.TypedValue("i", pass != null ? "0" : "1"), diff --git a/app/src/main/java/io/xpipe/app/util/RemoteDesktopWindow.java b/app/src/main/java/io/xpipe/app/util/RemoteDesktopWindow.java index 995e9ed7a..1eb99cad6 100644 --- a/app/src/main/java/io/xpipe/app/util/RemoteDesktopWindow.java +++ b/app/src/main/java/io/xpipe/app/util/RemoteDesktopWindow.java @@ -176,7 +176,7 @@ public class RemoteDesktopWindow { } public void focus() { - PlatformThread.runLaterIfNeeded(() -> { + ThreadHelper.runFailableAsync(() -> { model.focus(); }); }