mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-26 02:15:47 +00:00
Rework
This commit is contained in:
@@ -38,12 +38,10 @@ public class OptionsComp extends RegionBuilder<VBox> {
|
||||
|
||||
private final List<Entry> entries;
|
||||
private final List<Check> checks;
|
||||
private final boolean autoFocus;
|
||||
|
||||
public OptionsComp(List<Entry> entries, List<Check> checks, boolean autoFocus) {
|
||||
public OptionsComp(List<Entry> entries, List<Check> checks) {
|
||||
this.entries = entries;
|
||||
this.checks = checks;
|
||||
this.autoFocus = autoFocus;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -244,10 +242,6 @@ public class OptionsComp extends RegionBuilder<VBox> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!autoFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
var failed = checks.stream()
|
||||
.filter(check -> check.getValidationResult().getMessages().size() > 0)
|
||||
.findFirst();
|
||||
|
||||
@@ -7,11 +7,13 @@ import io.xpipe.app.comp.base.LabelComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.ValidationException;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.platform.Validator;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.process.ShellControl;
|
||||
import io.xpipe.app.pwman.PasswordManagerKeyConfiguration;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.util.Validators;
|
||||
import io.xpipe.core.KeyValue;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
@@ -27,7 +29,7 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@JsonTypeName("passwordManager")
|
||||
@JsonTypeName("passwordManagerAgent")
|
||||
@Value
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@@ -36,8 +38,6 @@ public class PasswordManagerAgentStrategy implements SshIdentityStrategy {
|
||||
@SuppressWarnings("unused")
|
||||
public static OptionsBuilder createOptions(
|
||||
Property<PasswordManagerAgentStrategy> p, SshIdentityStrategyChoiceConfig config) {
|
||||
var forward =
|
||||
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
|
||||
var identifier =
|
||||
new SimpleStringProperty(p.getValue() != null ? p.getValue().getIdentifier() : null);
|
||||
|
||||
@@ -69,22 +69,18 @@ public class PasswordManagerAgentStrategy implements SshIdentityStrategy {
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("passwordManagerSshKeyConfig")
|
||||
.addComp(pwmanDisplay)
|
||||
.hide(Bindings.or(pwmanProp.isNull(), new ReadOnlyBooleanWrapper(!config.isAllowPasswordAgentKeyChoice())))
|
||||
.hide(pwmanProp.isNull())
|
||||
.nameAndDescription(useKeyName() ? "agentKeyName" : "publicKey")
|
||||
.addComp(new SshAgentKeyListComp(config.getFileSystem(), p, identifier, useKeyName()), identifier)
|
||||
.hide(!config.isAllowPasswordAgentKeyChoice())
|
||||
.nameAndDescription("forwardAgent")
|
||||
.addToggle(forward)
|
||||
.nonNull()
|
||||
.hide(!config.isAllowAgentForward())
|
||||
.bind(
|
||||
() -> {
|
||||
return new PasswordManagerAgentStrategy(forward.get(), identifier.get());
|
||||
return new PasswordManagerAgentStrategy(identifier.get());
|
||||
},
|
||||
p);
|
||||
}
|
||||
|
||||
boolean forwardAgent;
|
||||
String identifier;
|
||||
|
||||
private static PasswordManagerKeyConfiguration getConfig() {
|
||||
@@ -99,6 +95,7 @@ public class PasswordManagerAgentStrategy implements SshIdentityStrategy {
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws ValidationException {
|
||||
Validators.nonNull(identifier);
|
||||
var config = getConfig();
|
||||
if (config == null) {
|
||||
throw new ValidationException(AppI18n.get("passwordManagerSshKeysNotSupported"));
|
||||
@@ -127,7 +124,7 @@ public class PasswordManagerAgentStrategy implements SshIdentityStrategy {
|
||||
public List<KeyValue> configOptions(ShellControl sc) throws Exception {
|
||||
var config = getConfig();
|
||||
if (config != null) {
|
||||
var strat = config.getSshIdentityStrategy(getPublicKeyStrategy().retrievePublicKey(), forwardAgent);
|
||||
var strat = config.getSshIdentityStrategy(getPublicKeyStrategy().retrievePublicKey(), false);
|
||||
return strat.configOptions(sc);
|
||||
} else {
|
||||
return List.of();
|
||||
|
||||
@@ -70,6 +70,7 @@ public class SshAgentKeyListComp extends SimpleRegionBuilder {
|
||||
popover.hide();
|
||||
e.consume();
|
||||
});
|
||||
entryButton.setMinWidth(600);
|
||||
content.getChildren().add(entryButton);
|
||||
}
|
||||
popover.setContentNode(content);
|
||||
|
||||
@@ -17,6 +17,5 @@ public class SshIdentityStrategyChoiceConfig {
|
||||
Supplier<Boolean> perUserKeyFileCheck;
|
||||
boolean allowKeyFileSync;
|
||||
boolean allowAgentForward;
|
||||
boolean allowPasswordAgentKeyChoice;
|
||||
ObservableValue<DataStoreEntryRef<ShellStore>> fileSystem;
|
||||
}
|
||||
|
||||
@@ -84,11 +84,6 @@ public class OptionsBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder disableAutoFocus() {
|
||||
focusEnabled = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder() {
|
||||
this.ownValidator = new SimpleValidator();
|
||||
this.allValidators.add(ownValidator);
|
||||
@@ -496,7 +491,7 @@ public class OptionsBuilder {
|
||||
|
||||
public OptionsComp buildComp() {
|
||||
finishCurrent();
|
||||
var comp = new OptionsComp(entries, focusFirstIncomplete ? allChecks : List.of(), focusEnabled);
|
||||
var comp = new OptionsComp(entries, focusFirstIncomplete ? allChecks : List.of());
|
||||
return comp;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@ public class BitwardenPasswordManager implements PasswordManager {
|
||||
.build();
|
||||
|
||||
return new OptionsBuilder()
|
||||
.disableAutoFocus()
|
||||
.addComp(syncButton)
|
||||
.nameAndDescription("passwordManagerTest")
|
||||
.addComp(new PasswordManagerTestComp(true))
|
||||
|
||||
@@ -37,7 +37,6 @@ public class DashlanePasswordManager implements PasswordManager {
|
||||
@SuppressWarnings("unused")
|
||||
public static OptionsBuilder createOptions(Property<DashlanePasswordManager> p) {
|
||||
return new OptionsBuilder()
|
||||
.disableAutoFocus()
|
||||
.nameAndDescription("passwordManagerTest")
|
||||
.addComp(new PasswordManagerTestComp(true));
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
return values;
|
||||
}
|
||||
|
||||
String constructKeeperInput(KeeperPasswordManager passwordManager) throws Exception;
|
||||
String constructKeeperInput(KeeperPasswordManager passwordManager, SecretValue password) throws Exception;
|
||||
|
||||
Duration getCacheDuration();
|
||||
|
||||
@@ -105,11 +105,13 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
return index;
|
||||
}
|
||||
|
||||
private void sendInitialSms() throws Exception {
|
||||
private boolean sendInitialSms(SecretValue password) throws Exception {
|
||||
var sc = getOrStartShell();
|
||||
var b = CommandBuilder.of()
|
||||
.add(getExecutable(), "get")
|
||||
.addLiteral("test");
|
||||
.addLiteral("xpipe-test")
|
||||
.add("--password")
|
||||
.addLiteral(password.getSecretValue());
|
||||
var file = sc.getSystemTemporaryDirectory().join("keeper" + Math.abs(new Random().nextInt()) + ".txt");
|
||||
var input = """
|
||||
|
||||
@@ -119,20 +121,30 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
""";
|
||||
sc.view().writeTextFile(file, input);
|
||||
|
||||
var fullCommand = CommandBuilder.of()
|
||||
var fullB = CommandBuilder.of()
|
||||
.add(sc.getShellDialect() == ShellDialects.CMD ? "type" : "cat")
|
||||
.addFile(file)
|
||||
.add("|")
|
||||
.add(b);
|
||||
sc.command(fullCommand).sensitive().execute();
|
||||
|
||||
var command = sc.command(fullB);
|
||||
command.killOnTimeout(CountDown.of().start(30_000));
|
||||
command.sensitive();
|
||||
var success = command.executeAndCheck();
|
||||
// A fail indicates the query went through but the entry was not found
|
||||
if (!success) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager) throws Exception {
|
||||
sendInitialSms();
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager, SecretValue password) throws Exception {
|
||||
var sent = sendInitialSms(password);
|
||||
|
||||
var index = getTotpDurationIndex();
|
||||
if (passwordManager.isHasCompletedRequestInSession() && index > 0) {
|
||||
if (!sent || (passwordManager.isHasCompletedRequestInSession() && index > 0)) {
|
||||
var input = """
|
||||
|
||||
1
|
||||
@@ -215,7 +227,7 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager) {
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager, SecretValue password) {
|
||||
var index = getTotpDurationIndex();
|
||||
if (passwordManager.isHasCompletedRequestInSession() && index > 0) {
|
||||
var input = """
|
||||
@@ -284,7 +296,7 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
class SecurityKey implements KeeperAuth {
|
||||
|
||||
@Override
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager) {
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager, SecretValue password) {
|
||||
var input = """
|
||||
|
||||
1
|
||||
@@ -337,7 +349,7 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager) {
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager, SecretValue password) {
|
||||
var input = """
|
||||
|
||||
1
|
||||
@@ -369,7 +381,7 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager) {
|
||||
public String constructKeeperInput(KeeperPasswordManager passwordManager, SecretValue password) {
|
||||
var input = """
|
||||
|
||||
1
|
||||
@@ -493,7 +505,7 @@ public class KeeperPasswordManager implements PasswordManager {
|
||||
FilePath file = sc.getSystemTemporaryDirectory().join("keeper" + Math.abs(new Random().nextInt()) + ".txt");
|
||||
|
||||
var effectiveTwoFactor = twoFactorAuth != null ? twoFactorAuth : new KeeperAuth.None();
|
||||
var input = effectiveTwoFactor.constructKeeperInput(this);
|
||||
var input = effectiveTwoFactor.constructKeeperInput(this, r);
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ public class LastpassPasswordManager implements PasswordManager {
|
||||
@SuppressWarnings("unused")
|
||||
public static OptionsBuilder createOptions(Property<LastpassPasswordManager> p) {
|
||||
return new OptionsBuilder()
|
||||
.disableAutoFocus()
|
||||
.nameAndDescription("passwordManagerTest")
|
||||
.addComp(new PasswordManagerTestComp(true));
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ public class OnePasswordManager implements PasswordManager {
|
||||
.build();
|
||||
|
||||
return new OptionsBuilder()
|
||||
.disableAutoFocus()
|
||||
.nameAndDescription("onePasswordManagerAccount")
|
||||
.addString(account)
|
||||
.hide(account.isNull().and(availableAccounts.emptyProperty()))
|
||||
|
||||
@@ -67,7 +67,6 @@ public class PassboltPasswordManager implements PasswordManager {
|
||||
chooser.setPrompt(new ReadOnlyObjectWrapper<>(FilePath.of("passbolt_private.asc")));
|
||||
|
||||
return new OptionsBuilder()
|
||||
.disableAutoFocus()
|
||||
.nameAndDescription("passboltServerUrl")
|
||||
.addComp(
|
||||
new TextFieldComp(serverUrl)
|
||||
|
||||
@@ -189,10 +189,10 @@ public interface PasswordManagerKeyStrategy {
|
||||
|
||||
static List<Class<?>> getClasses() {
|
||||
var l = new ArrayList<Class<?>>();
|
||||
l.add(Inline.class);
|
||||
l.add(Agent.class);
|
||||
l.add(KeePassXcOpenSshAgent.class);
|
||||
l.add(KeePassXcPageant.class);
|
||||
l.add(Inline.class);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ public class WindowsCredentialManager implements PasswordManager {
|
||||
@SuppressWarnings("unused")
|
||||
public static OptionsBuilder createOptions(Property<WindowsCredentialManager> p) {
|
||||
return new OptionsBuilder()
|
||||
.disableAutoFocus()
|
||||
.nameAndDescription("passwordManagerTest")
|
||||
.addComp(new PasswordManagerTestComp(true));
|
||||
}
|
||||
|
||||
@@ -234,3 +234,7 @@
|
||||
.ikonli-font-icon.graphic.terminal-dock-button {
|
||||
-fx-icon-color: -color-accent-fg;
|
||||
}
|
||||
|
||||
.text-field:focused {
|
||||
-fx-prompt-text-fill: -color-fg-subtle;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,6 @@ public class IdentityChoiceBuilder {
|
||||
.allowAgentForward(allowAgentForward)
|
||||
.allowKeyFileSync(true)
|
||||
.perUserKeyFileCheck(() -> false)
|
||||
.allowPasswordAgentKeyChoice(true)
|
||||
.fileSystem(fileSystem)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ public class LocalIdentityStoreProvider extends IdentityStoreProvider {
|
||||
var sshIdentityChoiceConfig = SshIdentityStrategyChoiceConfig.builder()
|
||||
.allowAgentForward(true)
|
||||
.allowKeyFileSync(false)
|
||||
.allowPasswordAgentKeyChoice(true)
|
||||
.perUserKeyFileCheck(() -> false)
|
||||
.build();
|
||||
|
||||
|
||||
+16
-4
@@ -17,9 +17,24 @@ import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PasswordManagerIdentityStoreProvider extends IdentityStoreProvider {
|
||||
|
||||
@Override
|
||||
public UUID getTargetCategory(DataStore store, UUID target) {
|
||||
PasswordManagerIdentityStore st = (PasswordManagerIdentityStore) store;
|
||||
if (!st.isPerUser()) {
|
||||
return target;
|
||||
}
|
||||
|
||||
var cat = DataStorage.get().getStoreCategoryIfPresent(target).orElseThrow();
|
||||
var inSynced = DataStorage.get().getCategoryParentHierarchy(cat).stream()
|
||||
.anyMatch(dataStoreCategory ->
|
||||
dataStoreCategory.getUuid().equals(DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID));
|
||||
return inSynced ? target : DataStorage.SYNCED_IDENTITIES_CATEGORY_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowCreation() {
|
||||
return AppPrefs.get().passwordManager().getValue() != null;
|
||||
@@ -33,12 +48,9 @@ public class PasswordManagerIdentityStoreProvider extends IdentityStoreProvider
|
||||
var sshKey = new SimpleObjectProperty<>(st.getSshKey());
|
||||
var perUser = new SimpleBooleanProperty(st.isPerUser());
|
||||
|
||||
var pwMan = AppPrefs.get().passwordManager().getValue();
|
||||
var showKeyChoice = pwMan == null || !pwMan.getKeyConfiguration().useInline();
|
||||
var sshIdentityChoiceConfig = SshIdentityStrategyChoiceConfig.builder()
|
||||
.allowAgentForward(true)
|
||||
.allowKeyFileSync(true)
|
||||
.allowPasswordAgentKeyChoice(showKeyChoice)
|
||||
.perUserKeyFileCheck(() -> false)
|
||||
.fileSystem(new ReadOnlyObjectWrapper<>(DataStorage.get().local().ref()))
|
||||
.build();
|
||||
@@ -48,7 +60,7 @@ public class PasswordManagerIdentityStoreProvider extends IdentityStoreProvider
|
||||
var hideSshKeyChoice = Bindings.createBooleanBinding(() -> {
|
||||
var pwman = AppPrefs.get().passwordManager().getValue();
|
||||
var strat = pwman.getKeyConfiguration();
|
||||
return !strat.useAgent() && !strat.useInline();
|
||||
return strat.useInline();
|
||||
}, AppPrefs.get().passwordManager());
|
||||
|
||||
var testComp = new PasswordManagerTestComp(key, false);
|
||||
|
||||
@@ -76,7 +76,6 @@ public class SyncedIdentityStoreProvider extends IdentityStoreProvider {
|
||||
var sshIdentityChoiceConfig = SshIdentityStrategyChoiceConfig.builder()
|
||||
.allowAgentForward(true)
|
||||
.allowKeyFileSync(true)
|
||||
.allowPasswordAgentKeyChoice(true)
|
||||
.perUserKeyFileCheck(() -> perUser.get())
|
||||
.build();
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -1639,7 +1639,7 @@ sshAgentSocketDescription=The custom socket to use to communicate with the SSH a
|
||||
publicKey=Key selector
|
||||
publicKeyDescription=The optional public key to force the agent to only offer the matching private key
|
||||
agentKeyName=Key selector
|
||||
agentKeyNameDescription=The optional key name to force the agent to only offer the matching key
|
||||
agentKeyNameDescription=The name of the key entry in the password manager
|
||||
actions=Actions
|
||||
hcloudServer.displayName=Hetzner cloud server
|
||||
hcloudServer.displayDescription=Access a server hosted on Hetzner cloud via SSH
|
||||
|
||||
Reference in New Issue
Block a user