From 0ac2acbbd577c537af0700807637d8d71fde2b76 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sat, 13 Sep 2025 10:13:48 +0000 Subject: [PATCH] Rework named pipe handling --- .../base/identity/ssh/PageantStrategy.java | 33 ++++++++----------- .../identity/ssh/SshIdentityStateManager.java | 19 +++++++++-- ext/base/src/main/java/module-info.java | 2 ++ 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/PageantStrategy.java b/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/PageantStrategy.java index 5b8f50696..010f8b777 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/PageantStrategy.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/PageantStrategy.java @@ -1,5 +1,8 @@ package io.xpipe.ext.base.identity.ssh; +import com.sun.jna.Memory; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinBase; import io.xpipe.app.comp.base.TextFieldComp; import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.prefs.AppPrefs; @@ -94,7 +97,7 @@ public class PageantStrategy implements SshIdentityStrategy { public void buildCommand(CommandBuilder builder) { builder.environment("SSH_AUTH_SOCK", parent -> { if (parent.getOsType() == OsType.WINDOWS) { - return getPageantWindowsPipe(parent); + return getPageantWindowsPipe(); } return null; @@ -111,27 +114,17 @@ public class PageantStrategy implements SshIdentityStrategy { new KeyValue("PKCS11Provider", "none")); } - private String getPageantWindowsPipe(ShellControl parent) throws Exception { - var name = parent.enforceDialect(ShellDialects.POWERSHELL, powershell -> { - var pipe = powershell.executeSimpleStringCommand( - "Get-ChildItem \"\\\\.\\pipe\\\" -recurse | Where-Object {$_.Name -match \"pageant\"} | foreach {echo $_.Name}"); - var lines = pipe.lines().toList(); - if (lines.isEmpty()) { - throw ErrorEventFactory.expected(new IllegalStateException("Pageant is not running")); - } + private String getPageantWindowsPipe() { + Memory p = new Memory(WinBase.WIN32_FIND_DATA.sizeOf()); + var r = Kernel32.INSTANCE.FindFirstFile("\\\\.\\pipe\\*pageant*", p); + if (r == WinBase.INVALID_HANDLE_VALUE) { + throw ErrorEventFactory.expected(new IllegalStateException("Pageant is not running")); + } - if (lines.size() > 1) { - var uname = powershell - .getShellDialect() - .printUsernameCommand(powershell) - .readStdoutOrThrow(); - return lines.stream().filter(s -> s.contains(uname)).findFirst().orElse(lines.getFirst()); - } + WinBase.WIN32_FIND_DATA fd = new WinBase.WIN32_FIND_DATA(p); + Kernel32.INSTANCE.FindClose(r); - return lines.getFirst(); - }); - - var file = "\\\\.\\pipe\\" + name; + var file = "\\\\.\\pipe\\" + fd.getFileName(); return file; } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/SshIdentityStateManager.java b/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/SshIdentityStateManager.java index ceb9892e0..2b9e79906 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/SshIdentityStateManager.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/identity/ssh/SshIdentityStateManager.java @@ -1,5 +1,8 @@ package io.xpipe.ext.base.identity.ssh; +import com.sun.jna.Memory; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinBase; import io.xpipe.app.issue.ErrorAction; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEventFactory; @@ -17,9 +20,21 @@ public class SshIdentityStateManager { private static RunningAgent runningAgent; + public static boolean checkNamedPipeExists(Path path) { + Memory p = new Memory(WinBase.WIN32_FIND_DATA.sizeOf()); + // This will not break the named pipe compared to using a normal exists check + var r = Kernel32.INSTANCE.FindFirstFile(path.toString(), p); + if (!WinBase.INVALID_HANDLE_VALUE.equals(r)) { + Kernel32.INSTANCE.FindClose(r); + return true; + } else { + return false; + } + } + private static void stopWindowsAgents(boolean openssh, boolean gpg, boolean external) throws Exception { var pipePath = Path.of("\\\\.\\pipe\\openssh-ssh-agent"); - if (!Files.exists(pipePath)) { + if (!checkNamedPipeExists(pipePath)) { return; } @@ -132,7 +147,7 @@ public class SshIdentityStateManager { stopWindowsAgents(true, true, false); var pipePath = Path.of("\\\\.\\pipe\\openssh-ssh-agent"); - var pipeExists = Files.exists(pipePath); + var pipeExists = checkNamedPipeExists(pipePath); if (!pipeExists) { // No agent is running throw ErrorEventFactory.expected(new IllegalStateException( diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index 0e50c6d26..25e2cafa2 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -29,6 +29,8 @@ open module io.xpipe.ext.base { requires static io.xpipe.app; requires org.kordamp.ikonli.javafx; requires atlantafx.base; + requires com.sun.jna.platform; + requires com.sun.jna; provides ActionProvider with LocalIdentityConvertHubLeafProvider,