mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-05-29 16:11:03 +00:00
More fixes for password managers
This commit is contained in:
@@ -11,8 +11,10 @@ import javafx.css.Size;
|
||||
import javafx.css.SizeUnits;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import lombok.Getter;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
@Getter
|
||||
public class ButtonComp extends Comp<CompStructure<Button>> {
|
||||
|
||||
private final ObservableValue<String> name;
|
||||
@@ -31,10 +33,6 @@ public class ButtonComp extends Comp<CompStructure<Button>> {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public ObservableValue<String> getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Node getGraphic() {
|
||||
return graphic.get();
|
||||
}
|
||||
@@ -43,10 +41,6 @@ public class ButtonComp extends Comp<CompStructure<Button>> {
|
||||
return graphic;
|
||||
}
|
||||
|
||||
public Runnable getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompStructure<Button> createBase() {
|
||||
var button = new Button(null);
|
||||
|
||||
@@ -39,6 +39,10 @@ public class AppLayoutModel {
|
||||
selected.setValue(entries.get(0));
|
||||
}
|
||||
|
||||
public void selectSettings() {
|
||||
selected.setValue(entries.get(2));
|
||||
}
|
||||
|
||||
public void selectConnections() {
|
||||
selected.setValue(entries.get(1));
|
||||
}
|
||||
|
||||
@@ -13,10 +13,12 @@ import javafx.beans.property.ObjectProperty;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.event.EventType;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class AppPreferencesFx {
|
||||
|
||||
private final PreferencesFxModel preferencesFxModel;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.prefs;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import com.dlsc.formsfx.model.structure.*;
|
||||
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleComboBoxControl;
|
||||
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleControl;
|
||||
@@ -10,15 +11,23 @@ import com.dlsc.preferencesfx.model.Setting;
|
||||
import com.dlsc.preferencesfx.util.VisibilityProperty;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppLayoutModel;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.AppTheme;
|
||||
import io.xpipe.app.ext.PrefsChoiceValue;
|
||||
import io.xpipe.app.ext.PrefsHandler;
|
||||
import io.xpipe.app.ext.PrefsProvider;
|
||||
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.util.ApplicationHelper;
|
||||
import io.xpipe.app.util.LockChangeAlert;
|
||||
import io.xpipe.app.util.LockedSecretValue;
|
||||
import io.xpipe.app.util.TerminalHelper;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.CommandControl;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.util.ModuleHelper;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import javafx.beans.binding.Bindings;
|
||||
@@ -30,6 +39,7 @@ import javafx.geometry.Pos;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import lombok.SneakyThrows;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
@@ -156,6 +166,10 @@ public class AppPrefs {
|
||||
private final BooleanField preferTerminalTabsField =
|
||||
BooleanField.ofBooleanType(preferTerminalTabs).render(() -> new CustomToggleControl());
|
||||
|
||||
// Password manager
|
||||
// ================
|
||||
private final StringProperty passwordManagerCommand = typed(new SimpleStringProperty(""), String.class);
|
||||
|
||||
// Start behaviour
|
||||
// ===============
|
||||
private final SimpleListProperty<StartupBehaviour> startupBehaviourList = new SimpleListProperty<>(
|
||||
@@ -163,9 +177,9 @@ public class AppPrefs {
|
||||
private final ObjectProperty<StartupBehaviour> startupBehaviour =
|
||||
typed(new SimpleObjectProperty<>(StartupBehaviour.GUI), StartupBehaviour.class);
|
||||
|
||||
private final SingleSelectionField<StartupBehaviour> startupBehaviourControl =
|
||||
Field.ofSingleSelectionType(startupBehaviourList, startupBehaviour)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
private final SingleSelectionField<StartupBehaviour> startupBehaviourControl = Field.ofSingleSelectionType(
|
||||
startupBehaviourList, startupBehaviour)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
|
||||
// Close behaviour
|
||||
// ===============
|
||||
@@ -209,10 +223,8 @@ public class AppPrefs {
|
||||
// =======
|
||||
private final ObjectProperty<Path> storageDirectory =
|
||||
typed(new SimpleObjectProperty<>(DEFAULT_STORAGE_DIR), Path.class);
|
||||
private final StringField storageDirectoryControl = PrefFields.ofPath(storageDirectory)
|
||||
.validate(
|
||||
CustomValidators.absolutePath(),
|
||||
CustomValidators.directory());
|
||||
private final StringField storageDirectoryControl =
|
||||
PrefFields.ofPath(storageDirectory).validate(CustomValidators.absolutePath(), CustomValidators.directory());
|
||||
|
||||
// Log level
|
||||
// =========
|
||||
@@ -240,30 +252,35 @@ public class AppPrefs {
|
||||
typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
private final BooleanField developerDisableUpdateVersionCheckField =
|
||||
BooleanField.ofBooleanType(developerDisableUpdateVersionCheck).render(() -> new CustomToggleControl());
|
||||
private final ObservableBooleanValue developerDisableUpdateVersionCheckEffective = bindDeveloperTrue(developerDisableUpdateVersionCheck);
|
||||
private final ObservableBooleanValue developerDisableUpdateVersionCheckEffective =
|
||||
bindDeveloperTrue(developerDisableUpdateVersionCheck);
|
||||
|
||||
private final BooleanProperty developerDisableGuiRestrictions =
|
||||
typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
private final BooleanField developerDisableGuiRestrictionsField =
|
||||
BooleanField.ofBooleanType(developerDisableGuiRestrictions).render(() -> new CustomToggleControl());
|
||||
private final ObservableBooleanValue developerDisableGuiRestrictionsEffective = bindDeveloperTrue(developerDisableGuiRestrictions);
|
||||
private final ObservableBooleanValue developerDisableGuiRestrictionsEffective =
|
||||
bindDeveloperTrue(developerDisableGuiRestrictions);
|
||||
|
||||
private final BooleanProperty developerShowHiddenProviders = typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
private final BooleanField developerShowHiddenProvidersField =
|
||||
BooleanField.ofBooleanType(developerShowHiddenProviders).render(() -> new CustomToggleControl());
|
||||
private final ObservableBooleanValue developerShowHiddenProvidersEffective = bindDeveloperTrue(developerShowHiddenProviders);
|
||||
private final ObservableBooleanValue developerShowHiddenProvidersEffective =
|
||||
bindDeveloperTrue(developerShowHiddenProviders);
|
||||
|
||||
private final BooleanProperty developerShowHiddenEntries = typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
private final BooleanField developerShowHiddenEntriesField =
|
||||
BooleanField.ofBooleanType(developerShowHiddenEntries).render(() -> new CustomToggleControl());
|
||||
private final ObservableBooleanValue developerShowHiddenEntriesEffective = bindDeveloperTrue(developerShowHiddenEntries);
|
||||
private final ObservableBooleanValue developerShowHiddenEntriesEffective =
|
||||
bindDeveloperTrue(developerShowHiddenEntries);
|
||||
|
||||
private final BooleanProperty developerDisableConnectorInstallationVersionCheck =
|
||||
typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
private final BooleanField developerDisableConnectorInstallationVersionCheckField = BooleanField.ofBooleanType(
|
||||
developerDisableConnectorInstallationVersionCheck)
|
||||
.render(() -> new CustomToggleControl());
|
||||
private final ObservableBooleanValue developerDisableConnectorInstallationVersionCheckEffective = bindDeveloperTrue(developerDisableConnectorInstallationVersionCheck);
|
||||
private final ObservableBooleanValue developerDisableConnectorInstallationVersionCheckEffective =
|
||||
bindDeveloperTrue(developerDisableConnectorInstallationVersionCheck);
|
||||
|
||||
public ReadOnlyProperty<CloseBehaviour> closeBehaviour() {
|
||||
return closeBehaviour;
|
||||
@@ -510,12 +527,70 @@ public class AppPrefs {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void selectCategory(int index) {
|
||||
AppLayoutModel.get().selectSettings();
|
||||
preferencesFx
|
||||
.getNavigationPresenter()
|
||||
.setSelectedCategory(preferencesFx.getCategories().get(index));
|
||||
}
|
||||
|
||||
public String passwordManagersString(String key) {
|
||||
if (passwordManagerCommand.get() == null
|
||||
|| passwordManagerCommand
|
||||
.get()
|
||||
.isEmpty()
|
||||
|| key == null
|
||||
|| key
|
||||
.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ApplicationHelper.replaceFileArgument(
|
||||
passwordManagerCommand.get(),
|
||||
"KEY",
|
||||
key);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AppPreferencesFx createPreferences() {
|
||||
var ctr = Setting.class.getDeclaredConstructor(String.class, Element.class, Property.class);
|
||||
ctr.setAccessible(true);
|
||||
|
||||
var testPasswordManagerValue = new SimpleStringProperty();
|
||||
var testPasswordManager = ctr.newInstance(
|
||||
"passwordManagerCommandTest",
|
||||
new LazyNodeElement<>(() -> new HorizontalComp(List.of(
|
||||
new TextFieldComp(testPasswordManagerValue)
|
||||
.apply(struc -> struc.get().setPromptText("Test password key"))
|
||||
.styleClass(Styles.LEFT_PILL),
|
||||
new ButtonComp(null, new FontIcon("mdi2p-play"), () -> {
|
||||
var cmd = passwordManagersString(testPasswordManagerValue.get());
|
||||
if (cmd == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
TerminalHelper.open(
|
||||
"Password test",
|
||||
new LocalStore()
|
||||
.control()
|
||||
.command(cmd)
|
||||
.terminalExitMode(
|
||||
CommandControl.TerminalExitMode
|
||||
.KEEP_OPEN)
|
||||
+ ShellDialects.getPlatformDefault()
|
||||
.getEchoCommand(
|
||||
"Is this your password?", false));
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
})
|
||||
.styleClass(Styles.RIGHT_PILL)))
|
||||
.createRegion()),
|
||||
null);
|
||||
var about = ctr.newInstance(null, new LazyNodeElement<>(() -> new AboutComp().createRegion()), null);
|
||||
var troubleshoot = ctr.newInstance(null, new LazyNodeElement<>(() -> new TroubleshootComp().createRegion()), null);
|
||||
var troubleshoot =
|
||||
ctr.newInstance(null, new LazyNodeElement<>(() -> new TroubleshootComp().createRegion()), null);
|
||||
|
||||
var categories = new ArrayList<>(List.of(
|
||||
Category.of("about", Group.of(about)),
|
||||
@@ -523,11 +598,7 @@ public class AppPrefs {
|
||||
"system",
|
||||
Group.of(
|
||||
"appBehaviour",
|
||||
Setting.of(
|
||||
"startupBehaviour",
|
||||
startupBehaviourControl,
|
||||
startupBehaviour
|
||||
),
|
||||
Setting.of("startupBehaviour", startupBehaviourControl, startupBehaviour),
|
||||
Setting.of("closeBehaviour", closeBehaviourControl, closeBehaviour)),
|
||||
Group.of("security", Setting.of("workspaceLock", lockCryptControl, lockCrypt)),
|
||||
Group.of(
|
||||
@@ -539,7 +610,9 @@ public class AppPrefs {
|
||||
Setting.of("updateToPrereleases", checkForPrereleasesField, checkForPrereleases)),
|
||||
group(
|
||||
"advanced",
|
||||
STORAGE_DIR_FIXED ? null : Setting.of("storageDirectory", storageDirectoryControl, storageDirectory),
|
||||
STORAGE_DIR_FIXED
|
||||
? null
|
||||
: Setting.of("storageDirectory", storageDirectoryControl, storageDirectory),
|
||||
Setting.of("logLevel", logLevelField, internalLogLevel),
|
||||
Setting.of("developerMode", developerModeField, internalDeveloperMode))),
|
||||
Category.of(
|
||||
@@ -551,6 +624,9 @@ public class AppPrefs {
|
||||
Setting.of("tooltipDelay", tooltipDelayInternal, tooltipDelayMin, tooltipDelayMax),
|
||||
Setting.of("language", languageControl, languageInternal)),
|
||||
Group.of("windowOptions", Setting.of("saveWindowLocation", saveWindowLocationInternal))),
|
||||
Category.of(
|
||||
"passwordManager",
|
||||
Group.of(Setting.of("passwordManagerCommand", passwordManagerCommand), testPasswordManager)),
|
||||
Category.of(
|
||||
"editor",
|
||||
Group.of(
|
||||
@@ -564,13 +640,14 @@ public class AppPrefs {
|
||||
editorReloadTimeoutMin,
|
||||
editorReloadTimeoutMax),
|
||||
Setting.of("preferEditorTabs", preferEditorTabsField, preferEditorTabs))),
|
||||
Category.of("terminal",
|
||||
Group.of(
|
||||
Setting.of("terminalProgram", terminalTypeControl, terminalType),
|
||||
Setting.of("customTerminalCommand", customTerminalCommandControl, customTerminalCommand)
|
||||
.applyVisibility(VisibilityProperty.of(
|
||||
terminalType.isEqualTo(ExternalTerminalType.CUSTOM))),
|
||||
Setting.of("preferTerminalTabs", preferTerminalTabsField, preferTerminalTabs))),
|
||||
Category.of(
|
||||
"terminal",
|
||||
Group.of(
|
||||
Setting.of("terminalProgram", terminalTypeControl, terminalType),
|
||||
Setting.of("customTerminalCommand", customTerminalCommandControl, customTerminalCommand)
|
||||
.applyVisibility(VisibilityProperty.of(
|
||||
terminalType.isEqualTo(ExternalTerminalType.CUSTOM))),
|
||||
Setting.of("preferTerminalTabs", preferTerminalTabsField, preferTerminalTabs))),
|
||||
Category.of(
|
||||
"developer",
|
||||
Setting.of(
|
||||
@@ -604,8 +681,9 @@ public class AppPrefs {
|
||||
return AppPreferencesFx.of(cats);
|
||||
}
|
||||
|
||||
private Group group(String name, Setting<?,?>... settings) {
|
||||
return Group.of(name, Arrays.stream(settings).filter(setting -> setting != null).toArray(Setting[]::new));
|
||||
private Group group(String name, Setting<?, ?>... settings) {
|
||||
return Group.of(
|
||||
name, Arrays.stream(settings).filter(setting -> setting != null).toArray(Setting[]::new));
|
||||
}
|
||||
|
||||
private class PrefsHandlerImpl implements PrefsHandler {
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -137,8 +138,8 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
throw new IllegalStateException("No custom editor command specified");
|
||||
}
|
||||
|
||||
var format = customCommand.contains("$file") ? customCommand : customCommand + " $file";
|
||||
ApplicationHelper.executeLocalApplication(sc -> ApplicationHelper.replaceFileArgument(format, "file", file.toString()), true);
|
||||
var format = customCommand.toLowerCase(Locale.ROOT).contains("$file") ? customCommand : customCommand + " $FILE";
|
||||
ApplicationHelper.executeLocalApplication(sc -> ApplicationHelper.replaceFileArgument(format, "FILE", file.toString()), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -447,9 +447,9 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||
throw new IllegalStateException("No custom terminal command specified");
|
||||
}
|
||||
|
||||
var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $cmd";
|
||||
var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $CMD";
|
||||
try (var pc = LocalStore.getShell()) {
|
||||
var toExecute = ApplicationHelper.replaceFileArgument(format, "cmd", file);
|
||||
var toExecute = ApplicationHelper.replaceFileArgument(format, "CMD", file);
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
toExecute = "start \"" + name + "\" " + toExecute;
|
||||
} else {
|
||||
|
||||
@@ -12,7 +12,9 @@ public class ApplicationHelper {
|
||||
|
||||
public static String replaceFileArgument(String format, String variable, String file) {
|
||||
// Support for legacy variables that were not upper case
|
||||
variable = variable.toUpperCase(Locale.ROOT);
|
||||
format = format.replace("$" + variable.toLowerCase(Locale.ROOT), "$" + variable.toUpperCase(Locale.ROOT));
|
||||
|
||||
var fileString = file.contains(" ") ? "\"" + file + "\"" : file;
|
||||
// Check if the variable is already quoted
|
||||
var replaced = format.replace("\"$" + variable + "\"", fileString).replace("$" + variable, fileString);
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
@@ -21,8 +22,8 @@ import java.util.function.Supplier;
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Reference.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.InPlace.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Prompt.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.Command.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.KeePass.class)
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.CustomCommand.class),
|
||||
@JsonSubTypes.Type(value = SecretRetrievalStrategy.PasswordManager.class)
|
||||
})
|
||||
public interface SecretRetrievalStrategy {
|
||||
|
||||
@@ -90,11 +91,33 @@ public interface SecretRetrievalStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("command")
|
||||
@JsonTypeName("passwordManager")
|
||||
@Builder
|
||||
@Jacksonized
|
||||
@Value
|
||||
public static class Command implements SecretRetrievalStrategy {
|
||||
public static class PasswordManager implements SecretRetrievalStrategy {
|
||||
|
||||
String key;
|
||||
|
||||
@Override
|
||||
public SecretValue retrieve(String displayName, DataStore store) throws Exception {
|
||||
var cmd = AppPrefs.get().passwordManagersString(key);
|
||||
if (cmd == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (var cc = new LocalStore().createBasicControl().command(cmd).start()) {
|
||||
var read = cc.readStdoutDiscardErr();
|
||||
return SecretHelper.encrypt(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("customCommand")
|
||||
@Builder
|
||||
@Jacksonized
|
||||
@Value
|
||||
public static class CustomCommand implements SecretRetrievalStrategy {
|
||||
|
||||
String command;
|
||||
|
||||
@@ -106,21 +129,4 @@ public interface SecretRetrievalStrategy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("keepass")
|
||||
@Builder
|
||||
@Jacksonized
|
||||
@Value
|
||||
public static class KeePass implements SecretRetrievalStrategy {
|
||||
|
||||
String entry;
|
||||
|
||||
@Override
|
||||
public SecretValue retrieve(String displayName, DataStore store) throws Exception {
|
||||
try (var cc = new LocalStore().createBasicControl().command(entry).start()) {
|
||||
var read = cc.readStdoutDiscardErr();
|
||||
return SecretHelper.encrypt(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.App;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.impl.HorizontalComp;
|
||||
import io.xpipe.app.fxcomps.impl.SecretFieldComp;
|
||||
import io.xpipe.app.fxcomps.impl.TextFieldComp;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class SecretRetrievalStrategyHelper {
|
||||
|
||||
private static OptionsBuilder inPlace(Property<SecretRetrievalStrategy.InPlace> p) {
|
||||
var secretProperty = new SimpleObjectProperty<>(
|
||||
p.getValue() != null ? p.getValue().getValue() : null);
|
||||
var secretProperty =
|
||||
new SimpleObjectProperty<>(p.getValue() != null ? p.getValue().getValue() : null);
|
||||
return new OptionsBuilder()
|
||||
.name("password")
|
||||
.addComp(new SecretFieldComp(secretProperty), secretProperty)
|
||||
@@ -22,16 +30,63 @@ public class SecretRetrievalStrategyHelper {
|
||||
p);
|
||||
}
|
||||
|
||||
private static OptionsBuilder passwordManager(Property<SecretRetrievalStrategy.PasswordManager> p) {
|
||||
var keyProperty =
|
||||
new SimpleObjectProperty<>(p.getValue() != null ? p.getValue().getKey() : null);
|
||||
var content = new HorizontalComp(List.<Comp<?>>of(
|
||||
new TextFieldComp(keyProperty).hgrow(),
|
||||
new ButtonComp(null, new FontIcon("mdomz-settings"), () -> {
|
||||
AppPrefs.get().selectCategory(3);
|
||||
App.getApp().getStage().requestFocus();
|
||||
})
|
||||
.grow(false, true)))
|
||||
.apply(struc -> struc.get().setSpacing(10));
|
||||
return new OptionsBuilder()
|
||||
.name("command")
|
||||
.addComp(content, keyProperty)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SecretRetrievalStrategy.PasswordManager(keyProperty.getValue());
|
||||
},
|
||||
p);
|
||||
}
|
||||
|
||||
private static OptionsBuilder customCommand(Property<SecretRetrievalStrategy.CustomCommand> p) {
|
||||
var cmdProperty =
|
||||
new SimpleObjectProperty<>(p.getValue() != null ? p.getValue().getCommand() : null);
|
||||
var content = new TextFieldComp(cmdProperty).apply(struc -> struc.get().setPromptText("Password key"));
|
||||
return new OptionsBuilder()
|
||||
.name("key")
|
||||
.addComp(content, cmdProperty)
|
||||
.bind(
|
||||
() -> {
|
||||
return new SecretRetrievalStrategy.CustomCommand(cmdProperty.getValue());
|
||||
},
|
||||
p);
|
||||
}
|
||||
|
||||
public static OptionsBuilder comp(Property<SecretRetrievalStrategy> s) {
|
||||
var inPlace = new SimpleObjectProperty<>(s.getValue() instanceof SecretRetrievalStrategy.InPlace i ? i : null);
|
||||
var command = new SimpleObjectProperty<>(s.getValue() instanceof SecretRetrievalStrategy.Command c ? c : null);
|
||||
SecretRetrievalStrategy strat = s.getValue();
|
||||
var inPlace = new SimpleObjectProperty<>(strat instanceof SecretRetrievalStrategy.InPlace i ? i : null);
|
||||
var passwordManager =
|
||||
new SimpleObjectProperty<>(strat instanceof SecretRetrievalStrategy.PasswordManager i ? i : null);
|
||||
var customCommand =
|
||||
new SimpleObjectProperty<>(strat instanceof SecretRetrievalStrategy.CustomCommand i ? i : null);
|
||||
var command = new SimpleObjectProperty<>(strat instanceof SecretRetrievalStrategy.CustomCommand c ? c : null);
|
||||
var map = new LinkedHashMap<String, OptionsBuilder>();
|
||||
map.put("none", new OptionsBuilder());
|
||||
map.put("password", inPlace(inPlace));
|
||||
map.put("passwordManager", passwordManager(passwordManager));
|
||||
map.put("customCommand", customCommand(customCommand));
|
||||
map.put("prompt", new OptionsBuilder());
|
||||
// map.put("command", new OptionsBuilder());
|
||||
map.put("keepass", new OptionsBuilder());
|
||||
var selected = new SimpleIntegerProperty();
|
||||
var selected = new SimpleIntegerProperty(
|
||||
strat instanceof SecretRetrievalStrategy.None
|
||||
? 0
|
||||
: strat instanceof SecretRetrievalStrategy.InPlace
|
||||
? 1
|
||||
: strat instanceof SecretRetrievalStrategy.PasswordManager
|
||||
? 2
|
||||
: strat instanceof SecretRetrievalStrategy.CustomCommand ? 3 : strat instanceof SecretRetrievalStrategy.Prompt ? 4 : 0);
|
||||
return new OptionsBuilder()
|
||||
.choice(selected, map)
|
||||
.bindChoice(
|
||||
@@ -39,9 +94,9 @@ public class SecretRetrievalStrategyHelper {
|
||||
return switch (selected.get()) {
|
||||
case 0 -> new SimpleObjectProperty<>(new SecretRetrievalStrategy.None());
|
||||
case 1 -> inPlace;
|
||||
case 2 -> new SimpleObjectProperty<>(new SecretRetrievalStrategy.Prompt());
|
||||
// case 3 -> command;
|
||||
case 3 -> new SimpleObjectProperty<>(new SecretRetrievalStrategy.KeePass("a"));
|
||||
case 2 -> passwordManager;
|
||||
case 3 -> customCommand;
|
||||
case 4 -> new SimpleObjectProperty<>(new SecretRetrievalStrategy.Prompt());
|
||||
default -> new SimpleObjectProperty<>();
|
||||
};
|
||||
},
|
||||
|
||||
@@ -64,10 +64,12 @@ developerMode=Developer mode
|
||||
developerModeDescription=When enabled, you will have access to a variety of additional options that are useful for development.
|
||||
editor=Editor
|
||||
custom=Custom
|
||||
passwordManagerCommand=Password manager command
|
||||
passwordManagerCommandDescription=The command to execute to fetch passwords. The placeholder string $KEY will be replaced by the quoted password key when called. This should call your password manager CLI to print the password to stdout, e.g. mypassmgr get $KEY.\n\nYou can check here whether the output is correct. The command should only output the password itself, no other formatting should be included in the output.
|
||||
preferEditorTabs=Prefer to open new tabs
|
||||
preferEditorTabsDescription=Controls whether XPipe will try to open new tabs in your chosen editor instead of new windows.
|
||||
customEditorCommand=Custom editor command
|
||||
customEditorCommandDescription=The command to execute to open the custom editor. The placeholder string $file will be replaced by the quoted absolute file name when called. Remember to quote your editor executable path if it contains spaces.
|
||||
customEditorCommandDescription=The command to execute to open the custom editor. The placeholder string $FILE will be replaced by the quoted absolute file name when called. Remember to quote your editor executable path if it contains spaces.
|
||||
editorReloadTimeout=Editor reload timeout
|
||||
editorReloadTimeoutDescription=The amount of milliseconds to wait before reading a file after it has been updated. This avoids issues in cases where your editor is slow at writing or releasing file locks.
|
||||
notepad++=Notepad++
|
||||
@@ -102,7 +104,7 @@ terminalProgram=Default program
|
||||
terminalProgramDescription=The default terminal to use when opening any kind of shell connection. This application is only used for display purposes, the started shell program depends on the shell connection itself.
|
||||
program=Program
|
||||
customTerminalCommand=Custom terminal command
|
||||
customTerminalCommandDescription=The command to execute to open the custom terminal. The placeholder string $cmd will be replaced by the quoted shell script file name when called. Remember to quote your terminal executable path if it contains spaces.
|
||||
customTerminalCommandDescription=The command to execute to open the custom terminal. The placeholder string $CMD will be replaced by the quoted shell script file name when called. Remember to quote your terminal executable path if it contains spaces.
|
||||
preferTerminalTabs=Prefer to open new tabs
|
||||
preferTerminalTabsDescription=Controls whether XPipe will try to open new tabs in your chosen terminal instead of new windows.
|
||||
cmd=cmd.exe
|
||||
|
||||
@@ -4,6 +4,10 @@ crlf=CRLF (Windows)
|
||||
lf=LF (Linux)
|
||||
none=None
|
||||
common=Common
|
||||
key=Key
|
||||
passwordManager=Password manager
|
||||
prompt=Prompt
|
||||
customCommand=Custom command
|
||||
other=Other
|
||||
setLock=Set lock
|
||||
changeLock=Change lock
|
||||
|
||||
Reference in New Issue
Block a user