Merge branch 'jump-server' into 17-release

This commit is contained in:
crschnick
2025-06-05 19:12:55 +00:00
parent 1c94d64e10
commit 40bb286267
9 changed files with 95 additions and 75 deletions
@@ -235,8 +235,8 @@ public class BrowserFileTransferOperation {
}
}
var noExt = target.getFileName().equals(target.getExtension());
return FilePath.of(target.getBaseName() + " (" + 1 + ")" + (noExt ? "" : "." + target.getExtension()));
var ext = target.getExtension();
return FilePath.of(target.getBaseName() + " (" + 1 + ")" + (ext.isPresent() ? "." + ext.get() : ""));
}
private void handleSingleAcrossFileSystems(FileEntry source) throws Exception {
@@ -85,7 +85,7 @@ public abstract class BrowserIconFileType {
var name = entry.getPath().getFileName();
var ext = entry.getPath().getExtension();
return (ext != null && endings.contains("." + ext.toLowerCase(Locale.ROOT))) || endings.contains(name);
return (ext.isPresent() && endings.contains("." + ext.get().toLowerCase(Locale.ROOT))) || endings.contains(name);
}
@Override
@@ -41,6 +41,7 @@ public enum DocumentationLink {
TUNNELS("guide/ssh-tunnels"),
HYPERV("guide/hyperv"),
SSH_MACS("guide/ssh#no-matching-mac-found"),
SSH_JUMP_SERVERS("guide/ssh#jump-servers"),
KEEPASSXC("guide/password-manager#keepassxc"),
PASSWORD_MANAGER("guide/password-manager"),
VNC_CLIENTS("guide/vnc#external-clients"),;
@@ -31,6 +31,7 @@ public class ShellDialects {
public static ShellDialect CONSTRAINED_POWERSHELL;
public static ShellDialect OVH_BASTION;
public static ShellDialect HETZNER_BOX;
public static ShellDialect JUMP_SERVER;
public static List<ShellDialect> getStartableDialects() {
return ALL.stream()
@@ -96,6 +97,7 @@ public class ShellDialects {
CONSTRAINED_POWERSHELL = byId("constrainedPowershell");
OVH_BASTION = byId("ovhBastion");
HETZNER_BOX = byId("hetznerBox");
JUMP_SERVER = byId("jumpServer");
}
}
}
@@ -21,7 +21,8 @@ public class ShellView {
public FilePath writeTextFileDeterministic(FilePath base, String text) throws Exception {
var hash = Math.abs(text.hashCode());
var target = FilePath.of(base.getBaseName().toString() + "-" + hash + "." + base.getExtension());
var ext = base.getExtension();
var target = FilePath.of(base.getBaseName().toString() + "-" + hash + (ext.isPresent() ? "." + ext.get() : ""));
if (fileExists(target)) {
return target;
}
@@ -6,10 +6,7 @@ import lombok.EqualsAndHashCode;
import lombok.NonNull;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.regex.Pattern;
public final class FilePath {
@@ -156,13 +153,13 @@ public final class FilePath {
return FilePath.of(value.substring(0, split));
}
public String getExtension() {
var name = FileNames.getFileName(value);
public Optional<String> getExtension() {
var name = getFileName();
var split = name.split("\\.");
if (split.length == 0) {
return null;
if (split.length < 2) {
return Optional.empty();
}
return split[split.length - 1];
return Optional.of(split[split.length - 1]);
}
public FilePath join(String... parts) {
@@ -0,0 +1,15 @@
package io.xpipe.core.util;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
@Value
@Builder
@Jacksonized
@AllArgsConstructor
public class KeyValue {
String key;
String value;
}
@@ -7,6 +7,8 @@ import io.xpipe.app.util.SecretRetrievalStrategy;
import io.xpipe.app.util.Validators;
import io.xpipe.core.process.*;
import io.xpipe.core.store.FileNames;
import io.xpipe.core.store.FilePath;
import io.xpipe.core.util.KeyValue;
import io.xpipe.core.util.ValidationException;
import com.fasterxml.jackson.annotation.JsonSubTypes;
@@ -18,6 +20,7 @@ import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.io.IOException;
import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@@ -32,12 +35,15 @@ import java.io.IOException;
@JsonSubTypes.Type(value = SshIdentityStrategy.OtherExternal.class)
})
public interface SshIdentityStrategy {
default void checkComplete() throws ValidationException {}
void prepareParent(ShellControl parent) throws Exception;
void buildCommand(CommandBuilder builder);
List<KeyValue> configOptions(ShellControl parent) throws Exception;
default SecretRetrievalStrategy getAskpassStrategy() {
return new SecretRetrievalStrategy.None();
}
@@ -50,9 +56,13 @@ public interface SshIdentityStrategy {
public void prepareParent(ShellControl parent) {}
@Override
public void buildCommand(CommandBuilder builder) {
public void buildCommand(CommandBuilder builder) {}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
// Don't use any agent keys to prevent too many authentication failures
builder.add("-oIdentitiesOnly=yes").add("-oIdentityAgent=none").add("-oIdentityFile=none");
return List.of(new KeyValue("IdentitiesOnly", "yes"), new KeyValue("IdentityAgent", "none"), new KeyValue("IdentityFile", "none"),
new KeyValue("PKCS11Provider", "none"));
}
}
@@ -94,12 +104,11 @@ public interface SshIdentityStrategy {
var pidEnvVariable = System.getenv("SSH_AGENT_PID");
return pidEnvVariable;
});
}
builder.add("-oIdentitiesOnly=no");
builder.add("-oIdentityFile=none");
if (forwardAgent) {
builder.add(1, "-A");
}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"), new KeyValue("IdentityFile", "none"), new KeyValue("PKCS11Provider", "none"));
}
}
@@ -131,8 +140,6 @@ public interface SshIdentityStrategy {
@Override
public void buildCommand(CommandBuilder builder) {
builder.add("-oIdentitiesOnly=no");
builder.add("-oIdentityFile=none");
builder.environment("SSH_AUTH_SOCK", parent -> {
if (parent.getOsType().equals(OsType.WINDOWS)) {
return getPageantWindowsPipe(parent);
@@ -140,9 +147,11 @@ public interface SshIdentityStrategy {
return null;
});
if (forwardAgent) {
builder.add(1, "-A");
}
}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"), new KeyValue("IdentityFile", "none"), new KeyValue("PKCS11Provider", "none"));
}
private String getPageantWindowsPipe(ShellControl parent) throws Exception {
@@ -191,12 +200,11 @@ public interface SshIdentityStrategy {
}
@Override
public void buildCommand(CommandBuilder builder) {
builder.add("-oIdentitiesOnly=no");
builder.add("-oIdentityFile=none");
if (forwardAgent) {
builder.add(1, "-A");
}
public void buildCommand(CommandBuilder builder) {}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"), new KeyValue("IdentityFile", "none"), new KeyValue("PKCS11Provider", "none"));
}
}
@@ -220,8 +228,6 @@ public interface SshIdentityStrategy {
@Override
public void buildCommand(CommandBuilder builder) {
builder.add("-oIdentitiesOnly=no");
builder.add("-oIdentityFile=none");
builder.environment("SSH_AUTH_SOCK", sc -> {
if (sc.getOsType() == OsType.WINDOWS) {
return null;
@@ -230,9 +236,11 @@ public interface SshIdentityStrategy {
var r = sc.executeSimpleStringCommand("gpgconf --list-dirs agent-ssh-socket");
return r;
});
if (forwardAgent) {
builder.add(1, "-A");
}
}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"), new KeyValue("IdentityFile", "none"), new KeyValue("PKCS11Provider", "none"));
}
}
@@ -304,29 +312,24 @@ public interface SshIdentityStrategy {
}
@Override
public void buildCommand(CommandBuilder builder) {
if (file == null) {
return;
public void buildCommand(CommandBuilder builder) {}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "yes"), new KeyValue("IdentityAgent", "none"),
new KeyValue("IdentityFile", resolveFilePath(parent).toString()), new KeyValue("PKCS11Provider", "none"));
}
private FilePath resolveFilePath(ShellControl sc) throws Exception {
var s = file.toAbsoluteFilePath(sc);
// The ~ is supported on all platforms, so manually replace it here for Windows
if (s.startsWith("~")) {
s = s.resolveTildeHome(sc.getOsType().getUserHomeDirectory(sc));
}
builder.add("-i")
.add(sc -> {
if (sc == null) {
return "\"" + file.toAbsoluteFilePath(null) + "\"";
}
var s = file.toAbsoluteFilePath(sc);
// The ~ is supported on all platforms, so manually replace it here for Windows
if (s.startsWith("~")) {
s = s.resolveTildeHome(sc.getOsType().getUserHomeDirectory(sc));
}
var resolved = sc.getShellDialect()
.evaluateExpression(sc, s.toString())
.readStdoutOrThrow();
return sc.getShellDialect().fileArgument(resolved);
})
.add("-oIdentitiesOnly=yes")
.add("-oIdentityAgent=none");
var resolved = sc.getShellDialect()
.evaluateExpression(sc, s.toString())
.readStdoutOrThrow();
return FilePath.of(resolved);
}
@Override
@@ -406,17 +409,14 @@ public interface SshIdentityStrategy {
var path = sc.view().getLibraryPath();
builder.fixedEnvironment("LD_LIBRARY_PATH", dir + ":" + path);
}
})
.add("-oIdentityFile=none")
.add("-I")
.add(sc -> {
if (sc == null) {
return "<ykcs path>";
}
return sc.getShellDialect().fileArgument(getFile(sc));
});
}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("PKCS11Provider", getFile(parent)),
new KeyValue("IdentityFile", "none"), new KeyValue("IdentityAgent", "none"));
}
}
@Value
@@ -450,8 +450,11 @@ public interface SshIdentityStrategy {
builder.fixedEnvironment("LD_LIBRARY_PATH", dir + ":" + path);
}
});
builder.add("-oIdentityFile=none");
builder.add("-I").addFile(file);
}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("PKCS11Provider", file), new KeyValue("IdentityFile", "none"), new KeyValue("IdentityAgent", "none"));
}
}
@@ -467,12 +470,11 @@ public interface SshIdentityStrategy {
public void prepareParent(ShellControl parent) {}
@Override
public void buildCommand(CommandBuilder builder) {
if (forwardAgent) {
builder.add(1, "-A");
}
builder.add("-oIdentityFile=none");
builder.add("-oIdentitiesOnly=no");
public void buildCommand(CommandBuilder builder) {}
@Override
public List<KeyValue> configOptions(ShellControl parent) throws Exception {
return List.of(new KeyValue("IdentitiesOnly", "no"), new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"), new KeyValue("IdentityFile", "none"), new KeyValue("PKCS11Provider", "none"));
}
}
}
+2
View File
@@ -1470,3 +1470,5 @@ vncConnections=VNC connections
passwordManagerIdentity=Password manager identity
passwordManagerIdentity.displayName=Password manager identity
passwordManagerIdentity.displayDescription=Retrieve the credentials of an identity from your password manager
useAsJumpServer=Jump server
useAsJumpServerDescription=This system is a jump server to be used with ProxyJump