mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-25 09:55:52 +00:00
Remote config fixes
This commit is contained in:
@@ -52,7 +52,7 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
||||
private ObservableValue<FilePath> prompt;
|
||||
|
||||
public <T extends FileSystemStore> ContextualFileReferenceChoiceComp(
|
||||
Property<DataStoreEntryRef<T>> fileSystem,
|
||||
ObservableValue<DataStoreEntryRef<T>> fileSystem,
|
||||
Property<FilePath> filePath,
|
||||
ContextualFileReferenceSync sync,
|
||||
List<PreviousFileReference> previousFileReferences,
|
||||
@@ -66,9 +66,6 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
||||
fileSystem.subscribe(val -> {
|
||||
this.fileSystem.setValue(val);
|
||||
});
|
||||
this.fileSystem.addListener((observable, oldValue, newValue) -> {
|
||||
fileSystem.setValue(newValue != null ? newValue.asNeeded() : null);
|
||||
});
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
@@ -85,7 +82,6 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
||||
fileStore -> {
|
||||
if (fileStore != null) {
|
||||
filePath.setValue(fileStore.getPath());
|
||||
fileSystem.setValue(fileStore.getFileSystem());
|
||||
}
|
||||
},
|
||||
false,
|
||||
|
||||
@@ -4,14 +4,18 @@ import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.comp.base.InputGroupComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.FileSystemStore;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.ext.ShellStore;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.platform.OptionsChoiceBuilder;
|
||||
import io.xpipe.app.secret.EncryptedValue;
|
||||
import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.secret.SecretStrategyChoiceConfig;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStorageUserHandler;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.ext.base.identity.ssh.SshIdentityStrategy;
|
||||
import io.xpipe.ext.base.identity.ssh.SshIdentityStrategyChoiceConfig;
|
||||
@@ -40,6 +44,7 @@ public class IdentityChoiceBuilder {
|
||||
boolean allowAgentForward;
|
||||
String userChoiceTranslationKey;
|
||||
ObservableValue<String> passwordChoiceTranslationKey;
|
||||
ObservableValue<DataStoreEntryRef<ShellStore>> fileSystem;
|
||||
|
||||
public IdentityChoiceBuilder(
|
||||
ObjectProperty<IdentityValue> identity,
|
||||
@@ -60,6 +65,7 @@ public class IdentityChoiceBuilder {
|
||||
this.allowAgentForward = allowAgentForward;
|
||||
this.userChoiceTranslationKey = userChoiceTranslationKey;
|
||||
this.passwordChoiceTranslationKey = new ReadOnlyStringWrapper(passwordChoiceTranslationKey);
|
||||
this.fileSystem = new ReadOnlyObjectWrapper<>(DataStorage.get().local().ref());
|
||||
}
|
||||
|
||||
public static OptionsBuilder ssh(ObjectProperty<IdentityValue> identity, boolean requireUser) {
|
||||
@@ -147,6 +153,7 @@ public class IdentityChoiceBuilder {
|
||||
.allowAgentForward(allowAgentForward)
|
||||
.allowKeyFileSync(true)
|
||||
.perUserKeyFileCheck(() -> false)
|
||||
.fileSystem(fileSystem)
|
||||
.build();
|
||||
|
||||
if (keyInput) {
|
||||
|
||||
@@ -97,7 +97,7 @@ public class CustomAgentStrategy implements SshIdentityStrategy {
|
||||
@Override
|
||||
public void buildCommand(CommandBuilder builder) {
|
||||
builder.environment("SSH_AUTH_SOCK", sc -> {
|
||||
if (sc.getOsType() == OsType.WINDOWS) {
|
||||
if (!sc.isLocal() || sc.getOsType() == OsType.WINDOWS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -113,8 +113,8 @@ public class CustomAgentStrategy implements SshIdentityStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(publicKey);
|
||||
public List<KeyValue> configOptions(ShellControl sc) throws Exception {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey);
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"),
|
||||
new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"),
|
||||
|
||||
+14
-4
@@ -48,12 +48,22 @@ public class CustomPkcs11LibraryStrategy implements SshIdentityStrategy {
|
||||
.nameAndDescription("pkcs11Library")
|
||||
.addComp(
|
||||
new ContextualFileReferenceChoiceComp(
|
||||
new ReadOnlyObjectWrapper<>(
|
||||
DataStorage.get().local().ref()),
|
||||
config.getFileSystem() != null ? config.getFileSystem() : new ReadOnlyObjectWrapper<>(DataStorage.get().local().ref()),
|
||||
file,
|
||||
null,
|
||||
List.of(),
|
||||
e -> e.equals(DataStorage.get().local()),
|
||||
e -> {
|
||||
if (config.getFileSystem() == null) {
|
||||
return e.equals(DataStorage.get().local());
|
||||
}
|
||||
|
||||
var fs = config.getFileSystem().getValue();
|
||||
if (fs == null) {
|
||||
return e.equals(DataStorage.get().local());
|
||||
} else {
|
||||
return e.equals(fs.get());
|
||||
}
|
||||
},
|
||||
false),
|
||||
file)
|
||||
.nonNull()
|
||||
@@ -95,7 +105,7 @@ public class CustomPkcs11LibraryStrategy implements SshIdentityStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
public List<KeyValue> configOptions(ShellControl sc) {
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", "no"),
|
||||
new KeyValue("PKCS11Provider", "\"" + file.toString() + "\""),
|
||||
|
||||
@@ -103,8 +103,8 @@ public class GpgAgentStrategy implements SshIdentityStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(publicKey);
|
||||
public List<KeyValue> configOptions(ShellControl sc) throws Exception {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey);
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"),
|
||||
new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"),
|
||||
|
||||
@@ -136,7 +136,7 @@ public class InPlaceKeyStrategy implements SshIdentityStrategy {
|
||||
return;
|
||||
}
|
||||
|
||||
var file = getTargetFilePath();
|
||||
var file = getTargetFilePath(parent);
|
||||
if (parent.view().fileExists(file)) {
|
||||
return;
|
||||
}
|
||||
@@ -156,18 +156,20 @@ public class InPlaceKeyStrategy implements SshIdentityStrategy {
|
||||
.execute();
|
||||
}
|
||||
|
||||
LocalFileTracker.deleteOnExit(file.asLocalPath());
|
||||
if (parent.isLocal()) {
|
||||
LocalFileTracker.deleteOnExit(file.asLocalPath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildCommand(CommandBuilder builder) {}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
public List<KeyValue> configOptions(ShellControl sc) {
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", "yes"),
|
||||
new KeyValue("IdentityAgent", "none"),
|
||||
new KeyValue("IdentityFile", "\"" + getTargetFilePath() + "\""),
|
||||
new KeyValue("IdentityFile", "\"" + getTargetFilePath(sc) + "\""),
|
||||
new KeyValue("PKCS11Provider", "none"));
|
||||
}
|
||||
|
||||
@@ -176,11 +178,10 @@ public class InPlaceKeyStrategy implements SshIdentityStrategy {
|
||||
return password;
|
||||
}
|
||||
|
||||
private FilePath getTargetFilePath() {
|
||||
var temp = AppSystemInfo.ofCurrent()
|
||||
.getTemp()
|
||||
.resolve("xpipe-"
|
||||
private FilePath getTargetFilePath(ShellControl sc) {
|
||||
var temp = sc.getSystemTemporaryDirectory()
|
||||
.join("xpipe-"
|
||||
+ Math.abs(Objects.hash(this, AppSystemInfo.ofCurrent().getUser())) + ".key");
|
||||
return FilePath.of(temp);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.xpipe.app.platform.LabelGraphic;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.platform.OptionsChoiceBuilder;
|
||||
import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.process.LocalShell;
|
||||
import io.xpipe.app.process.ShellControl;
|
||||
import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.secret.SecretStrategyChoiceConfig;
|
||||
@@ -37,8 +38,6 @@ import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
@Value
|
||||
@@ -104,20 +103,21 @@ public class KeyFileStrategy implements SshIdentityStrategy {
|
||||
});
|
||||
var generateButton = new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2c-cog-refresh-outline"), () -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
Path path = keyPath.get().asLocalPath();
|
||||
if (!Files.exists(path)) {
|
||||
var sc = config.getFileSystem() != null ? config.getFileSystem().getValue().getStore().getOrStartSession() : LocalShell.getShell();
|
||||
var path = keyPath.get();
|
||||
if (!sc.view().fileExists(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pubKeyPath = Path.of(path + ".pub");
|
||||
if (Files.exists(pubKeyPath)) {
|
||||
var contents = Files.readString(pubKeyPath).strip();
|
||||
var pubKeyPath = FilePath.of(path + ".pub");
|
||||
if (sc.view().fileExists(pubKeyPath)) {
|
||||
var contents = sc.view().readTextFile(pubKeyPath).strip();
|
||||
Platform.runLater(() -> {
|
||||
publicKey.set(contents);
|
||||
});
|
||||
}
|
||||
|
||||
var contents = Files.readAllBytes(path);
|
||||
var contents = sc.view().readRawFile(path);
|
||||
var generated = ProcessControlProvider.get()
|
||||
.generatePublicSshKey(InPlaceSecretValue.of(contents), keyPasswordProperty.get());
|
||||
if (generated != null) {
|
||||
@@ -143,12 +143,22 @@ public class KeyFileStrategy implements SshIdentityStrategy {
|
||||
.description("locationDescription")
|
||||
.addComp(
|
||||
new ContextualFileReferenceChoiceComp(
|
||||
new ReadOnlyObjectWrapper<>(
|
||||
DataStorage.get().local().ref()),
|
||||
config.getFileSystem() != null ? config.getFileSystem() : new ReadOnlyObjectWrapper<>(DataStorage.get().local().ref()),
|
||||
keyPath,
|
||||
config.isAllowKeyFileSync() ? sync : null,
|
||||
List.of(),
|
||||
e -> e.equals(DataStorage.get().local()),
|
||||
e -> {
|
||||
if (config.getFileSystem() == null) {
|
||||
return e.equals(DataStorage.get().local());
|
||||
}
|
||||
|
||||
var fs = config.getFileSystem().getValue();
|
||||
if (fs == null) {
|
||||
return e.equals(DataStorage.get().local());
|
||||
} else {
|
||||
return e.equals(fs.get());
|
||||
}
|
||||
},
|
||||
false),
|
||||
keyPath)
|
||||
.nonNull()
|
||||
@@ -232,11 +242,11 @@ public class KeyFileStrategy implements SshIdentityStrategy {
|
||||
public void buildCommand(CommandBuilder builder) {}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
public List<KeyValue> configOptions(ShellControl sc) {
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", "yes"),
|
||||
new KeyValue("IdentityAgent", "none"),
|
||||
new KeyValue("IdentityFile", "\"" + resolveFilePath().toString() + "\""),
|
||||
new KeyValue("IdentityFile", "\"" + resolveFilePath(sc).toString() + "\""),
|
||||
new KeyValue("PKCS11Provider", "none"));
|
||||
}
|
||||
|
||||
@@ -245,8 +255,8 @@ public class KeyFileStrategy implements SshIdentityStrategy {
|
||||
return password;
|
||||
}
|
||||
|
||||
private FilePath resolveFilePath() {
|
||||
var s = file.toLocalAbsoluteFilePath();
|
||||
private FilePath resolveFilePath(ShellControl sc) {
|
||||
var s = file.toAbsoluteFilePath(sc);
|
||||
// The ~ is supported on all platforms, so manually replace it here for Windows
|
||||
if (s.startsWith("~")) {
|
||||
s = s.resolveTildeHome(FilePath.of(AppSystemInfo.ofCurrent().getUserHome()));
|
||||
|
||||
@@ -20,7 +20,7 @@ public class NoIdentityStrategy implements SshIdentityStrategy {
|
||||
public void buildCommand(CommandBuilder builder) {}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
public List<KeyValue> configOptions(ShellControl sc) {
|
||||
// Don't use any agent keys to prevent too many authentication failures
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", "yes"),
|
||||
|
||||
@@ -84,8 +84,8 @@ public class OpenSshAgentStrategy implements SshIdentityStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(publicKey);
|
||||
public List<KeyValue> configOptions(ShellControl sc) throws Exception {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey);
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"),
|
||||
new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"),
|
||||
|
||||
+2
-2
@@ -61,8 +61,8 @@ public class OtherExternalAgentStrategy implements SshIdentityStrategy {
|
||||
public void buildCommand(CommandBuilder builder) {}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(publicKey);
|
||||
public List<KeyValue> configOptions(ShellControl sc) throws Exception {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey);
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"),
|
||||
new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"),
|
||||
|
||||
@@ -95,7 +95,7 @@ public class PageantStrategy implements SshIdentityStrategy {
|
||||
@Override
|
||||
public void buildCommand(CommandBuilder builder) {
|
||||
builder.environment("SSH_AUTH_SOCK", parent -> {
|
||||
if (parent.getOsType() == OsType.WINDOWS) {
|
||||
if (parent.isLocal() && parent.getOsType() == OsType.WINDOWS) {
|
||||
return getPageantWindowsPipe();
|
||||
}
|
||||
|
||||
@@ -104,8 +104,8 @@ public class PageantStrategy implements SshIdentityStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(publicKey);
|
||||
public List<KeyValue> configOptions(ShellControl sc) throws Exception {
|
||||
var file = SshIdentityStrategy.getPublicKeyPath(sc, publicKey);
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", file.isPresent() ? "yes" : "no"),
|
||||
new KeyValue("ForwardAgent", forwardAgent ? "yes" : "no"),
|
||||
|
||||
@@ -58,23 +58,22 @@ public interface SshIdentityStrategy {
|
||||
return l;
|
||||
}
|
||||
|
||||
static Optional<FilePath> getPublicKeyPath(String publicKey) {
|
||||
static Optional<FilePath> getPublicKeyPath(ShellControl sc, String publicKey) throws Exception {
|
||||
if (publicKey == null || publicKey.isBlank()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
var isFile = OsFileSystem.ofLocal().isProbableFilePath(publicKey);
|
||||
if (isFile && Files.exists(Paths.get(publicKey))) {
|
||||
return Optional.ofNullable(FilePath.parse(publicKey));
|
||||
var isFile = OsFileSystem.of(sc.getOsType()).isProbableFilePath(publicKey);
|
||||
if (isFile && sc.view().fileExists(FilePath.of(publicKey))) {
|
||||
return Optional.of(FilePath.of(publicKey));
|
||||
}
|
||||
|
||||
try {
|
||||
var base = LocalShell.getShell().getSystemTemporaryDirectory().join("key.pub");
|
||||
var file = LocalShell.getShell().view().writeTextFileDeterministic(base, publicKey.strip() + "\n");
|
||||
var base = sc.getSystemTemporaryDirectory().join("key.pub");
|
||||
var file = sc.view().writeTextFileDeterministic(base, publicKey.strip() + "\n");
|
||||
|
||||
if (OsType.ofLocal() != OsType.WINDOWS) {
|
||||
LocalShell.getShell()
|
||||
.command(CommandBuilder.of().add("chmod", "400").addFile(file))
|
||||
if (sc.getOsType() != OsType.WINDOWS) {
|
||||
sc.command(CommandBuilder.of().add("chmod", "400").addFile(file))
|
||||
.executeAndCheck();
|
||||
}
|
||||
|
||||
@@ -95,7 +94,7 @@ public interface SshIdentityStrategy {
|
||||
|
||||
void buildCommand(CommandBuilder builder);
|
||||
|
||||
List<KeyValue> configOptions();
|
||||
List<KeyValue> configOptions(ShellControl sc) throws Exception;
|
||||
|
||||
default SecretRetrievalStrategy getAskpassStrategy() {
|
||||
return new SecretNoneStrategy();
|
||||
|
||||
+5
@@ -1,5 +1,9 @@
|
||||
package io.xpipe.ext.base.identity.ssh;
|
||||
|
||||
import io.xpipe.app.ext.FileSystemStore;
|
||||
import io.xpipe.app.ext.ShellStore;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
@@ -12,4 +16,5 @@ public class SshIdentityStrategyChoiceConfig {
|
||||
Supplier<Boolean> perUserKeyFileCheck;
|
||||
boolean allowKeyFileSync;
|
||||
boolean allowAgentForward;
|
||||
ObservableValue<DataStoreEntryRef<ShellStore>> fileSystem;
|
||||
}
|
||||
|
||||
@@ -26,10 +26,9 @@ import java.util.List;
|
||||
@AllArgsConstructor
|
||||
public class YubikeyPivStrategy implements SshIdentityStrategy {
|
||||
|
||||
private String getFile() {
|
||||
private String getFile(ShellControl sc) {
|
||||
var file =
|
||||
switch (OsType.ofLocal()) {
|
||||
case OsType.Linux ignored -> "/usr/local/lib/libykcs11.so";
|
||||
switch (sc.getOsType()) {
|
||||
case OsType.MacOs ignored -> "/usr/local/lib/libykcs11.dylib";
|
||||
case OsType.Windows ignored -> {
|
||||
var x64 = "C:\\Program Files\\Yubico\\Yubico PIV Tool\\bin\\libykcs11.dll";
|
||||
@@ -44,6 +43,7 @@ public class YubikeyPivStrategy implements SshIdentityStrategy {
|
||||
|
||||
yield x64;
|
||||
}
|
||||
default -> "/usr/local/lib/libykcs11.so";
|
||||
};
|
||||
return file;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class YubikeyPivStrategy implements SshIdentityStrategy {
|
||||
public void prepareParent(ShellControl parent) throws Exception {
|
||||
parent.requireLicensedFeature(LicenseProvider.get().getFeature("pkcs11Identity"));
|
||||
|
||||
var file = getFile();
|
||||
var file = getFile(parent);
|
||||
if (!parent.getShellDialect().createFileExistsCommand(parent, file).executeAndCheck()) {
|
||||
throw ErrorEventFactory.expected(new IOException("Yubikey PKCS11 library at " + file + " not found"));
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class YubikeyPivStrategy implements SshIdentityStrategy {
|
||||
@Override
|
||||
public void buildCommand(CommandBuilder builder) {
|
||||
builder.setup(sc -> {
|
||||
var file = getFile();
|
||||
var file = getFile(sc);
|
||||
var dir = FilePath.of(file).getParent();
|
||||
if (sc.getOsType() == OsType.WINDOWS) {
|
||||
builder.addToPath(dir, true);
|
||||
@@ -72,10 +72,10 @@ public class YubikeyPivStrategy implements SshIdentityStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> configOptions() {
|
||||
public List<KeyValue> configOptions(ShellControl sc) {
|
||||
return List.of(
|
||||
new KeyValue("IdentitiesOnly", "no"),
|
||||
new KeyValue("PKCS11Provider", "\"" + getFile() + "\""),
|
||||
new KeyValue("PKCS11Provider", "\"" + getFile(sc) + "\""),
|
||||
new KeyValue("IdentityFile", "none"),
|
||||
new KeyValue("IdentityAgent", "none"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user