diff --git a/app/src/main/java/io/xpipe/app/cred/CustomAgentStrategy.java b/app/src/main/java/io/xpipe/app/cred/CustomAgentStrategy.java index a7c9880d3..52a95f79f 100644 --- a/app/src/main/java/io/xpipe/app/cred/CustomAgentStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/CustomAgentStrategy.java @@ -132,13 +132,13 @@ public class CustomAgentStrategy implements SshIdentityAgentStrategy { public List configOptions(ShellControl sc) throws Exception { var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey); var l = new ArrayList<>(List.of( - new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"), - new KeyValue("IdentityFile", file.isPresent() ? file.get().toString() : "none"), - new KeyValue("PKCS11Provider", "none"))); + KeyValue.raw("IdentitiesOnly", file.isPresent() ? "yes" : "no"), + KeyValue.raw("IdentityFile", file.isPresent() ? file.get().toString() : "none"), + KeyValue.raw("PKCS11Provider", "none"))); var agent = determinetAgentSocketLocation(sc); if (agent != null) { - l.add(new KeyValue("IdentityAgent", "\"" + agent + "\"")); + l.add(KeyValue.escape("IdentityAgent", agent)); } return l; diff --git a/app/src/main/java/io/xpipe/app/cred/CustomPkcs11LibraryStrategy.java b/app/src/main/java/io/xpipe/app/cred/CustomPkcs11LibraryStrategy.java index d51faa689..8ca31a892 100644 --- a/app/src/main/java/io/xpipe/app/cred/CustomPkcs11LibraryStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/CustomPkcs11LibraryStrategy.java @@ -110,10 +110,10 @@ public class CustomPkcs11LibraryStrategy implements SshIdentityStrategy { @Override public List configOptions(ShellControl sc) { return List.of( - new KeyValue("IdentitiesOnly", "no"), - new KeyValue("PKCS11Provider", "\"" + file.toString() + "\""), - new KeyValue("IdentityFile", "none"), - new KeyValue("IdentityAgent", "none")); + KeyValue.raw("IdentitiesOnly", "no"), + KeyValue.escape("PKCS11Provider", file), + KeyValue.raw("IdentityFile", "none"), + KeyValue.raw("IdentityAgent", "none")); } public PublicKeyStrategy getPublicKeyStrategy() { diff --git a/app/src/main/java/io/xpipe/app/cred/GpgAgentStrategy.java b/app/src/main/java/io/xpipe/app/cred/GpgAgentStrategy.java index 7da2ac589..06ed055a0 100644 --- a/app/src/main/java/io/xpipe/app/cred/GpgAgentStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/GpgAgentStrategy.java @@ -96,13 +96,13 @@ public class GpgAgentStrategy implements SshIdentityAgentStrategy { public List configOptions(ShellControl sc) throws Exception { var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey); var l = new ArrayList<>(List.of( - new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"), - new KeyValue("IdentityFile", file.isPresent() ? file.get().toString() : "none"), - new KeyValue("PKCS11Provider", "none"))); + KeyValue.raw("IdentitiesOnly", file.isPresent() ? "yes" : "no"), + KeyValue.escape("IdentityFile", file.isPresent() ? file.get() : "none"), + KeyValue.raw("PKCS11Provider", "none"))); var agent = determinetAgentSocketLocation(sc); if (agent != null) { - l.add(new KeyValue("IdentityAgent", "\"" + agent + "\"")); + l.add(KeyValue.escape("IdentityAgent", agent)); } return l; diff --git a/app/src/main/java/io/xpipe/app/cred/InPlaceKeyStrategy.java b/app/src/main/java/io/xpipe/app/cred/InPlaceKeyStrategy.java index 383dce771..0c69b9f52 100644 --- a/app/src/main/java/io/xpipe/app/cred/InPlaceKeyStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/InPlaceKeyStrategy.java @@ -167,10 +167,10 @@ public class InPlaceKeyStrategy implements SshIdentityStrategy { @Override public List configOptions(ShellControl sc) { return List.of( - new KeyValue("IdentitiesOnly", "yes"), - new KeyValue("IdentityAgent", "none"), - new KeyValue("IdentityFile", "\"" + getTargetFilePath(sc) + "\""), - new KeyValue("PKCS11Provider", "none")); + KeyValue.raw("IdentitiesOnly", "yes"), + KeyValue.raw("IdentityAgent", "none"), + KeyValue.escape("IdentityFile", getTargetFilePath(sc)), + KeyValue.raw("PKCS11Provider", "none")); } @Override diff --git a/app/src/main/java/io/xpipe/app/cred/KeyFileStrategy.java b/app/src/main/java/io/xpipe/app/cred/KeyFileStrategy.java index 264cfa899..54c180bc3 100644 --- a/app/src/main/java/io/xpipe/app/cred/KeyFileStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/KeyFileStrategy.java @@ -249,10 +249,10 @@ public class KeyFileStrategy implements SshIdentityStrategy { @Override public List configOptions(ShellControl sc) { return List.of( - new KeyValue("IdentitiesOnly", "yes"), - new KeyValue("IdentityAgent", "none"), - new KeyValue("IdentityFile", "\"" + resolveFilePath(sc).toString() + "\""), - new KeyValue("PKCS11Provider", "none")); + KeyValue.raw("IdentitiesOnly", "yes"), + KeyValue.raw("IdentityAgent", "none"), + KeyValue.escape("IdentityFile", resolveFilePath(sc)), + KeyValue.raw("PKCS11Provider", "none")); } @Override diff --git a/app/src/main/java/io/xpipe/app/cred/NoIdentityStrategy.java b/app/src/main/java/io/xpipe/app/cred/NoIdentityStrategy.java index b856912c8..02c4b7a9d 100644 --- a/app/src/main/java/io/xpipe/app/cred/NoIdentityStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/NoIdentityStrategy.java @@ -23,10 +23,10 @@ public class NoIdentityStrategy implements SshIdentityStrategy { public List configOptions(ShellControl sc) { // Don't use any agent keys to prevent too many authentication failures return List.of( - new KeyValue("IdentitiesOnly", "yes"), - new KeyValue("IdentityAgent", "none"), - new KeyValue("IdentityFile", "none"), - new KeyValue("PKCS11Provider", "none")); + KeyValue.raw("IdentitiesOnly", "yes"), + KeyValue.raw("IdentityAgent", "none"), + KeyValue.raw("IdentityFile", "none"), + KeyValue.raw("PKCS11Provider", "none")); } @Override diff --git a/app/src/main/java/io/xpipe/app/cred/OpenSshAgentStrategy.java b/app/src/main/java/io/xpipe/app/cred/OpenSshAgentStrategy.java index 2f446c5d7..f19a65341 100644 --- a/app/src/main/java/io/xpipe/app/cred/OpenSshAgentStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/OpenSshAgentStrategy.java @@ -80,13 +80,13 @@ public class OpenSshAgentStrategy implements SshIdentityAgentStrategy { public List configOptions(ShellControl sc) throws Exception { var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey); var l = new ArrayList<>(List.of( - new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"), - new KeyValue("IdentityFile", file.isPresent() ? file.get().toString() : "none"), - new KeyValue("PKCS11Provider", "none"))); + KeyValue.raw("IdentitiesOnly", file.isPresent() ? "yes" : "no"), + KeyValue.escape("IdentityFile", file.isPresent() ? file.get() : "none"), + KeyValue.raw("PKCS11Provider", "none"))); var agent = determinetAgentSocketLocation(sc); if (agent != null) { - l.add(new KeyValue("IdentityAgent", "\"" + agent + "\"")); + l.add(KeyValue.escape("IdentityAgent", agent)); } return l; diff --git a/app/src/main/java/io/xpipe/app/cred/OtherExternalAgentStrategy.java b/app/src/main/java/io/xpipe/app/cred/OtherExternalAgentStrategy.java index 296ebb24c..53697fdaf 100644 --- a/app/src/main/java/io/xpipe/app/cred/OtherExternalAgentStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/OtherExternalAgentStrategy.java @@ -60,9 +60,9 @@ public class OtherExternalAgentStrategy implements SshIdentityAgentStrategy { public List configOptions(ShellControl sc) throws Exception { var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey); return List.of( - new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"), - new KeyValue("IdentityFile", file.isPresent() ? file.get().toString() : "none"), - new KeyValue("PKCS11Provider", "none")); + KeyValue.raw("IdentitiesOnly", file.isPresent() ? "yes" : "no"), + KeyValue.escape("IdentityFile", file.isPresent() ? file.get() : "none"), + KeyValue.raw("PKCS11Provider", "none")); } public PublicKeyStrategy getPublicKeyStrategy() { diff --git a/app/src/main/java/io/xpipe/app/cred/PageantStrategy.java b/app/src/main/java/io/xpipe/app/cred/PageantStrategy.java index acddcae04..36d688a11 100644 --- a/app/src/main/java/io/xpipe/app/cred/PageantStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/PageantStrategy.java @@ -102,13 +102,13 @@ public class PageantStrategy implements SshIdentityAgentStrategy { public List configOptions(ShellControl sc) throws Exception { var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey); var l = new ArrayList<>(List.of( - new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"), - new KeyValue("IdentityFile", file.isPresent() ? file.get().toString() : "none"), - new KeyValue("PKCS11Provider", "none"))); + KeyValue.raw("IdentitiesOnly", file.isPresent() ? "yes" : "no"), + KeyValue.escape("IdentityFile", file.isPresent() ? file.get() : "none"), + KeyValue.raw("PKCS11Provider", "none"))); var agent = determinetAgentSocketLocation(sc); if (agent != null) { - l.add(new KeyValue("IdentityAgent", "\"" + agent + "\"")); + l.add(KeyValue.escape("IdentityAgent", agent)); } return l; diff --git a/app/src/main/java/io/xpipe/app/cred/YubikeyPivStrategy.java b/app/src/main/java/io/xpipe/app/cred/YubikeyPivStrategy.java index 86e98e9dd..8a00746e1 100644 --- a/app/src/main/java/io/xpipe/app/cred/YubikeyPivStrategy.java +++ b/app/src/main/java/io/xpipe/app/cred/YubikeyPivStrategy.java @@ -74,10 +74,10 @@ public class YubikeyPivStrategy implements SshIdentityStrategy { @Override public List configOptions(ShellControl sc) { return List.of( - new KeyValue("IdentitiesOnly", "no"), - new KeyValue("PKCS11Provider", "\"" + getFile(sc) + "\""), - new KeyValue("IdentityFile", "none"), - new KeyValue("IdentityAgent", "none")); + KeyValue.raw("IdentitiesOnly", "no"), + KeyValue.escape("PKCS11Provider", getFile(sc)), + KeyValue.raw("IdentityFile", "none"), + KeyValue.raw("IdentityAgent", "none")); } @Override diff --git a/app/src/main/java/io/xpipe/app/pwman/PasswordManagerKeyStrategy.java b/app/src/main/java/io/xpipe/app/pwman/PasswordManagerKeyStrategy.java index d8d9c7f01..61eda9454 100644 --- a/app/src/main/java/io/xpipe/app/pwman/PasswordManagerKeyStrategy.java +++ b/app/src/main/java/io/xpipe/app/pwman/PasswordManagerKeyStrategy.java @@ -216,13 +216,12 @@ public interface PasswordManagerKeyStrategy { public List configOptions(ShellControl sc) throws Exception { var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey); var l = new ArrayList<>(List.of( - new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"), - new KeyValue("ForwardAgent", forward ? "yes" : "no"), - new KeyValue( - "IdentityFile", file.isPresent() ? file.get().toString() : "none"), - new KeyValue("PKCS11Provider", "none"))); + KeyValue.raw("IdentitiesOnly", file.isPresent() ? "yes" : "no"), + KeyValue.raw("ForwardAgent", forward ? "yes" : "no"), + KeyValue.escape("IdentityFile", file.isPresent() ? file.get() : "none"), + KeyValue.raw("PKCS11Provider", "none"))); if (socket != null) { - l.add(new KeyValue("IdentityAgent", "\"" + socket + "\"")); + l.add(KeyValue.escape("IdentityAgent", socket)); } return l; } diff --git a/core/src/main/java/io/xpipe/core/KeyValue.java b/core/src/main/java/io/xpipe/core/KeyValue.java index 01c945b81..dc8e30aa0 100644 --- a/core/src/main/java/io/xpipe/core/KeyValue.java +++ b/core/src/main/java/io/xpipe/core/KeyValue.java @@ -1,5 +1,6 @@ package io.xpipe.core; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Value; @@ -8,8 +9,26 @@ import lombok.extern.jackson.Jacksonized; @Value @Builder @Jacksonized -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class KeyValue { + + public static KeyValue raw(String key, String value) { + return new KeyValue(key, value); + } + + public static KeyValue escape(String key, Object value) { + var string = value.toString(); + + string = string.replaceAll("\\\\", "\\\\\\\\"); + + var isQuoted = string.startsWith("\"") && string.endsWith("\""); + if (!isQuoted && string.contains(" ")) { + string = "\"" + string + "\""; + } + + return new KeyValue(key, string); + } + String key; String value; }