This commit is contained in:
crschnick
2025-06-18 11:14:41 +00:00
parent 39b2c1f082
commit 2fd358caef
10 changed files with 111 additions and 39 deletions

View File

@@ -226,11 +226,6 @@ public class StoreCreationModel {
validate();
commit(true);
} catch (Throwable ex) {
var changedStore = !store.getValue().equals(entry.getValue().getStore());
if (changedStore) {
int a = 0;
}
if (ex instanceof ValidationException) {
ErrorEventFactory.expected(ex);
} else if (ex instanceof StackOverflowError) {
@@ -263,6 +258,8 @@ public class StoreCreationModel {
if (unsupported) {
ss.stopSessionIfNeeded();
}
} else if (s instanceof ValidatableStore vs) {
vs.validate();
}
}

View File

@@ -120,10 +120,14 @@ public class StoreEntryListOverviewComp extends SimpleComp {
private Region createAddButton() {
var menu = new MenuButton(null, new FontIcon("mdi2p-plus-thick"));
menu.setOnShowing(event -> {
menu.getItems().clear();
StoreCreationMenu.addButtons(menu, true);
event.consume();
});
menu.textProperty().bind(AppI18n.observable("new"));
menu.setAlignment(Pos.CENTER);
menu.setTextAlignment(TextAlignment.CENTER);
StoreCreationMenu.addButtons(menu, true);
menu.setOpacity(0.85);
menu.setMinWidth(Region.USE_PREF_SIZE);
return menu;

View File

@@ -50,7 +50,7 @@ public class PasswordManagerCategory extends AppPrefsCategory {
.build();
var choice = choiceBuilder.build().buildComp();
var testInput = new PasswordManagerTestComp(testPasswordManagerValue);
var testInput = new PasswordManagerTestComp(testPasswordManagerValue, true);
testInput.maxWidth(getCompWidth());
testInput.hgrow();

View File

@@ -1,6 +1,7 @@
package io.xpipe.app.prefs;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.HorizontalComp;
@@ -15,6 +16,7 @@ import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Region;
@@ -27,9 +29,11 @@ import java.util.List;
public class PasswordManagerTestComp extends SimpleComp {
private final StringProperty value;
private final boolean handleEnter;
public PasswordManagerTestComp(StringProperty value) {
public PasswordManagerTestComp(StringProperty value, boolean handleEnter) {
this.value = value;
this.handleEnter = handleEnter;
}
@Override
@@ -37,32 +41,34 @@ public class PasswordManagerTestComp extends SimpleComp {
var prefs = AppPrefs.get();
var testPasswordManagerResult = new SimpleStringProperty();
var testInput = new HorizontalComp(List.<Comp<?>>of(
new TextFieldComp(value)
.apply(struc -> struc.get()
.promptTextProperty()
.bind(Bindings.createStringBinding(
() -> {
return prefs.passwordManager.getValue() != null
? prefs.passwordManager
.getValue()
.getKeyPlaceholder()
: "?";
},
prefs.passwordManager)))
.styleClass(Styles.LEFT_PILL)
.hgrow()
.apply(struc -> struc.get().setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
testPasswordManager(value.get(), testPasswordManagerResult);
event.consume();
}
})),
new ButtonComp(null, new FontIcon("mdi2p-play"), () -> {
testPasswordManager(value.get(), testPasswordManagerResult);
})
.tooltip(AppI18n.observable("test"))
.styleClass(Styles.RIGHT_PILL)));
var field = new TextFieldComp(value)
.apply(struc -> struc.get()
.promptTextProperty()
.bind(Bindings.createStringBinding(
() -> {
return prefs.passwordManager.getValue() != null
? prefs.passwordManager
.getValue()
.getKeyPlaceholder()
: "?";
},
prefs.passwordManager)))
.styleClass(Styles.LEFT_PILL)
.hgrow();
if (handleEnter) {
field.apply(struc -> struc.get().setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
testPasswordManager(value.get(), testPasswordManagerResult);
event.consume();
}
}));
}
var button = new ButtonComp(null, new FontIcon("mdi2p-play"), () -> {
testPasswordManager(value.get(), testPasswordManagerResult);
}).tooltip(AppI18n.observable("test")).styleClass(Styles.RIGHT_PILL);
var testInput = new HorizontalComp(List.<Comp<?>>of(field, button));
testInput.apply(struc -> {
struc.get().setFillHeight(true);
var first = ((Region) struc.get().getChildren().get(0));

View File

@@ -1,20 +1,67 @@
## File browser
- The file browser now works much better in small windows sizes
- Actions which modify a single file will now automatically refresh the file list to show updated changes
- There is now a new file browser action to compute directory sizes
- Renaming a file now moves the caret to the end of the base file name
- Fix file renaming not working if previous rename operation was cancelled
- The transfer speed in the file browser on Windows for multiple files has been optimized
- Fix file transfer kill button sometimes not working when transfer was frozen
- Fix terminal sometimes not being launched with the correct working directory of the current path
- Fix file deletion not showing errors when the operation failed in cmd
- Fix various rare race condition errors when closing a file system tab
## Connection hub
- Renaming connection entries can now be done quickly without having to open the configuration dialog
- You can now set connection configurations to be frozen, meaning that the connection entry can't be modified or deleted. This is helpful for templating and team vault setups
- When editing an incomplete connection configuration, the focus will automatically jump to the first incomplete/invalid value. This makes keyboard usage easier
- Password managers now support retrieving both username and password of an entry. For that, you can now create password manager identities that automatically provide the username and password
## VNC
Up until now, the internal VNC implementation of XPipe did a somewhat acceptable job for most connections. However, it is not able to match dedicated VNC clients when it comes to more advanced features and authentication methods. There's simply not Le development capacity to maintain all of these additional VNC features. For this reason, there is now support to also use an external VNC client with XPipe, it just as with any other tool integrations.
The current integrations include:
- TigerVNC
- TightVNC
- RealVNC
- Remmina
- macOS screen sharing
- A custom command
## SSH
They are two major changes regarding SSH in this release.
First, there is now proper support for jump servers. While gateways worked similar to jump servers, they were a different concept and did not work for cases where the ProxyJump functionality was required. You can now configure an SSH connection in its advanced settings to be treated as a jump server. This will result in XPipe using the ProxyJump syntax when this connection is used as a gateway for other SSH connections. This works for all kinds of connections, including config connections.
Second, the SSH implementation for devices that don't provide a full shell, e.g. embedded devices and other limited systems, has been completely reworked. This fixes many issues where connections to such systems were not possible or failed. You can now designate an SSH connection as a limited system in its advanced settings, even without the homelab plan. This will then allow you to directly launch the connection, without any issues.
## Actions
There is now a new action system, which maps most UI actions to fixed schemas. Essentially, this means that you can now automate almost any action you can perform from the UI via desktop shortcuts, URLs, HTTP API calls, and more. You can configure action shortcuts with the new action configuration dialog and control how to call the action from it.
Furthermore, it is also now possible to control how all of these actions are run. For production systems, for example, you can configure that all actions that perform some kind of modification, like deleting a file, have to be confirmed first. This gives you an added layer of protection to double-check any operation before actually executing it.
## macOS 26 Tahoe
The
## Other
- Terminal connections now enable truecolor mode if possible
- The option to open a connection in VSCode remote has been expanded to also support Cursor and Windsurf
- Implement various performance improvements
- You can now specify an alternative user for shell environments to switch to via sudo
- You can now specify a git username and password in the settings menu if your local system does not have a git client with configured credentials
- You can now disable icon sources without having to remove them
- There is now a native Windows ARM build
- Active tunnels are now periodically refreshed to check if the underlying tunnel was closed
- Fix clipboard data of other formats, e.g. files, being cleared after expiration of a copied password
- Fix pwsh connections on Linux/macOS freezing on sudo elevation
- Fix sudo elevation not working on WSL if WSLInterop for executables was disabled
- There is now a notification when a password is copied to the clipboard
- There is now a new loading icon
-

View File

@@ -41,7 +41,8 @@ public abstract class IdentityStoreProvider implements DataStoreProvider {
@Override
public ObservableValue<String> informationString(StoreSection section) {
var st = (IdentityStore) section.getWrapper().getStore().getValue();
var s = (st.getUsername() != null ? "User " + st.getUsername() : "Anonymous user")
var user = st.getUsername().hasUser() ? st.getUsername().getFixedUsername().map(s -> "User " + s).orElse("User") : "Anonymous User";
var s = user
+ (st.getPassword() == null || st.getPassword() instanceof SecretRetrievalStrategy.None
? ""
: " + Password")

View File

@@ -7,6 +7,7 @@ import io.xpipe.app.util.*;
import io.xpipe.core.store.InternalCacheDataStore;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.core.store.ValidatableStore;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value;
@@ -22,7 +23,7 @@ import java.time.Instant;
@Value
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PasswordManagerIdentityStore extends IdentityStore implements InternalCacheDataStore {
public class PasswordManagerIdentityStore extends IdentityStore implements InternalCacheDataStore, ValidatableStore {
String key;
@@ -56,6 +57,14 @@ public class PasswordManagerIdentityStore extends IdentityStore implements Inter
throw ErrorEventFactory.expected(new UnsupportedOperationException("Credentials were requested but not supplied"));
}
if (r.getUsername() == null) {
throw ErrorEventFactory.expected(new UnsupportedOperationException("Identity " + key + " does not include username"));
}
if (r.getPassword() == null) {
throw ErrorEventFactory.expected(new UnsupportedOperationException("Identity " + key + " does not include a password"));
}
setCache("lastQueried", Instant.now());
setCache("credential", r);
@@ -105,4 +114,9 @@ public class PasswordManagerIdentityStore extends IdentityStore implements Inter
public SshIdentityStrategy getSshIdentity() {
return new SshIdentityStrategy.None();
}
@Override
public void validate() throws Exception {
retrieveCredentials();
}
}

View File

@@ -29,7 +29,7 @@ public class PasswordManagerIdentityStoreProvider extends IdentityStoreProvider
var key = new SimpleStringProperty(st.getKey());
var comp = new PasswordManagerTestComp(key);
var comp = new PasswordManagerTestComp(key, false);
return new OptionsBuilder()
.nameAndDescription("passwordManagerKey")
.addComp(comp.hgrow(), key)

View File

@@ -52,6 +52,7 @@ open module io.xpipe.ext.base {
DesktopApplicationStoreProvider,
LocalIdentityStoreProvider,
SyncedIdentityStoreProvider,
PasswordManagerIdentityStoreProvider,
ScriptGroupStoreProvider;
provides DataStorageExtensionProvider with
ScriptDataStorageProvider;

View File

@@ -1032,7 +1032,8 @@ dockerRunningScan=Running docker containers
dockerAllScan=All docker containers
wslScan=WSL instances
sshScan=SSH config connections
requiresElevation=Run Elevated
runAsUser=Run as user
runAsUserDescription=Start this shell environment as a different user
default=Default
administrator=Administrator
wslHost=WSL Host
@@ -1480,7 +1481,8 @@ customVncCommandDescription=The custom command to execute to launch VNC sessions
vncConnections=VNC connections
passwordManagerIdentity=Password manager identity
passwordManagerIdentity.displayName=Password manager identity
passwordManagerIdentity.displayDescription=Retrieve the credentials of an identity from your password manager
#force
passwordManagerIdentity.displayDescription=Retrieve username and password of an identity from your password manager
useAsJumpServer=Jump server
useAsJumpServerDescription=This system is a jump server to be used with ProxyJump
passwordCopied=Connection password copied to clipboard