mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-16 15:32:26 -04:00
Cleanup
This commit is contained in:
67 files changed
+294
-228
No files matched your search
@@ -1,6 +1,5 @@
|
||||
package io.xpipe.app.beacon;
|
||||
|
||||
import io.xpipe.app.process.ShellControl;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.store.ShellStore;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.util.BooleanScope;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
@@ -15,7 +17,6 @@ import io.modelcontextprotocol.server.McpServerFeatures;
|
||||
import io.modelcontextprotocol.server.McpSyncServer;
|
||||
import io.modelcontextprotocol.spec.HttpHeaders;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.Value;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
@@ -55,9 +56,8 @@ public class AppMcpServer {
|
||||
|
||||
McpSyncServer syncServer = io.modelcontextprotocol.server.McpServer.sync(transportProvider)
|
||||
.serverInfo(AppNames.ofCurrent().getName(), AppProperties.get().getVersion())
|
||||
.capabilities(McpSchema.ServerCapabilities.builder()
|
||||
.tools(false)
|
||||
.build())
|
||||
.capabilities(
|
||||
McpSchema.ServerCapabilities.builder().tools(false).build())
|
||||
.instructions(effectivePrompt)
|
||||
.build();
|
||||
|
||||
@@ -108,8 +108,10 @@ public class AppMcpServer {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try (var ignored = new BooleanScope(showingError).start()) {
|
||||
ErrorEventFactory.fromMessage(
|
||||
"An external request was made to the XPipe MCP server, however the MCP server is not enabled in the" +
|
||||
" settings menu").expected().handle();
|
||||
"An external request was made to the XPipe MCP server, however the MCP server is not enabled in the"
|
||||
+ " settings menu")
|
||||
.expected()
|
||||
.handle();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -125,7 +127,9 @@ public class AppMcpServer {
|
||||
if (!showingError.get()) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try (var ignored = new BooleanScope(showingError).start()) {
|
||||
ErrorEventFactory.fromMessage(msg).expected().handle();
|
||||
ErrorEventFactory.fromMessage(msg)
|
||||
.expected()
|
||||
.handle();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -141,9 +145,11 @@ public class AppMcpServer {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try (var ignored = new BooleanScope(showingError).start()) {
|
||||
ErrorEventFactory.fromMessage(
|
||||
"An external request was made to the XPipe MCP server without the header Authorization set. " +
|
||||
"Please configure your MCP client with the Bearer API token you can find the API " +
|
||||
"settings menu").expected().handle();
|
||||
"An external request was made to the XPipe MCP server without the header Authorization set. "
|
||||
+ "Please configure your MCP client with the Bearer API token you can find the API "
|
||||
+ "settings menu")
|
||||
.expected()
|
||||
.handle();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -159,7 +165,8 @@ public class AppMcpServer {
|
||||
if (!showingError.get()) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try (var ignored = new BooleanScope(showingError).start()) {
|
||||
ErrorEventFactory.fromMessage("The Authorization header sent by the MCP client is not correct")
|
||||
ErrorEventFactory.fromMessage(
|
||||
"The Authorization header sent by the MCP client is not correct")
|
||||
.expected()
|
||||
.handle();
|
||||
}
|
||||
|
||||
@@ -90,12 +90,15 @@ public final class McpTools {
|
||||
|
||||
var handshakeRequest = HandshakeExchange.Request.builder()
|
||||
.client(BeaconClientInformation.Mcp.builder().build())
|
||||
.auth(BeaconAuthMethod.ApiKey.builder().key(AppPrefs.get().apiKey().get()).build())
|
||||
.auth(BeaconAuthMethod.ApiKey.builder()
|
||||
.key(AppPrefs.get().apiKey().get())
|
||||
.build())
|
||||
.build();
|
||||
var handshakeReq = HttpRequest.newBuilder()
|
||||
.uri(URI.create(
|
||||
"http://localhost:" + AppBeaconServer.get().getPort() + "/handshake"))
|
||||
.POST(HttpRequest.BodyPublishers.ofString(JacksonMapper.getDefault().writeValueAsString(handshakeRequest)))
|
||||
.POST(HttpRequest.BodyPublishers.ofString(
|
||||
JacksonMapper.getDefault().writeValueAsString(handshakeRequest)))
|
||||
.build();
|
||||
var handshakeRes = HttpHelper.client().send(handshakeReq, HttpResponse.BodyHandlers.ofString());
|
||||
var handshakeResJson = JacksonMapper.getDefault().readTree(handshakeRes.body());
|
||||
@@ -106,15 +109,14 @@ public final class McpTools {
|
||||
.build();
|
||||
}
|
||||
|
||||
var handshakeResObject = JacksonMapper.getDefault().treeToValue(handshakeResJson, HandshakeExchange.Response.class);
|
||||
var handshakeResObject =
|
||||
JacksonMapper.getDefault().treeToValue(handshakeResJson, HandshakeExchange.Response.class);
|
||||
var token = handshakeResObject.getSessionToken();
|
||||
|
||||
var httpReq = HttpRequest.newBuilder()
|
||||
.uri(URI.create(
|
||||
"http://localhost:" + AppBeaconServer.get().getPort() + path))
|
||||
.header(
|
||||
"Authorization",
|
||||
"Bearer " + token)
|
||||
.header("Authorization", "Bearer " + token)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(payloadJson.toPrettyString()))
|
||||
.build();
|
||||
var httpRes = HttpHelper.client().send(httpReq, HttpResponse.BodyHandlers.ofString());
|
||||
@@ -446,7 +448,8 @@ public final class McpTools {
|
||||
.orElseThrow(),
|
||||
AppNames.extModuleName("base") + ".script.ScriptStore");
|
||||
var method = clazz.getDeclaredMethod("assembleScriptChain", ShellControl.class, boolean.class);
|
||||
var command = (String) method.invoke(script.getStore(), shellSession.getControl(), arguments != null);
|
||||
var command =
|
||||
(String) method.invoke(script.getStore(), shellSession.getControl(), arguments != null);
|
||||
var scriptFile = ScriptHelper.createExecScript(shellSession.getControl(), command);
|
||||
var out = shellSession
|
||||
.getControl()
|
||||
|
||||
@@ -249,17 +249,21 @@ public class ModalOverlayComp extends RegionBuilder<Region> {
|
||||
});
|
||||
// Let largest button use its own pref size to always take the pref width, even if constrained
|
||||
// and make users use max size
|
||||
node.minWidthProperty().bind(Bindings.createDoubleBinding(() -> {
|
||||
if (node.equals(maxNode.get())) {
|
||||
if (node.getWidth() <= 70) {
|
||||
return 70.0;
|
||||
} else {
|
||||
return Region.USE_PREF_SIZE;
|
||||
}
|
||||
} else {
|
||||
return max.get();
|
||||
}
|
||||
}, node.widthProperty(), max));
|
||||
node.minWidthProperty()
|
||||
.bind(Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
if (node.equals(maxNode.get())) {
|
||||
if (node.getWidth() <= 70) {
|
||||
return 70.0;
|
||||
} else {
|
||||
return Region.USE_PREF_SIZE;
|
||||
}
|
||||
} else {
|
||||
return max.get();
|
||||
}
|
||||
},
|
||||
node.widthProperty(),
|
||||
max));
|
||||
node.prefHeightProperty().bind(buttonBar.heightProperty());
|
||||
}
|
||||
buttonBar.getChildren().add(node);
|
||||
|
||||
@@ -153,8 +153,7 @@ public class AppLayoutModel {
|
||||
|
||||
private void showPrefsRestartDialog() {
|
||||
if (!AppOperationMode.isInShutdown()) {
|
||||
var modal = ModalOverlay.of(
|
||||
"prefsRestartTitle", AppDialog.dialogTextKey("prefsRestartContent"));
|
||||
var modal = ModalOverlay.of("prefsRestartTitle", AppDialog.dialogTextKey("prefsRestartContent"));
|
||||
modal.addButton(ModalButton.cancel());
|
||||
modal.addButton(new ModalButton("restart", () -> AppRestart.restart(), true, true));
|
||||
modal.show();
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AppLocalTemp {
|
||||
|
||||
@@ -29,7 +28,9 @@ public class AppLocalTemp {
|
||||
}
|
||||
|
||||
if (Files.isSymbolicLink(temp)) {
|
||||
ErrorEventFactory.fromThrowable(new IOException("Invalid file type for " + temp)).term().handle();
|
||||
ErrorEventFactory.fromThrowable(new IOException("Invalid file type for " + temp))
|
||||
.term()
|
||||
.handle();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -37,7 +38,9 @@ public class AppLocalTemp {
|
||||
temp = temp.resolve(user);
|
||||
|
||||
if (Files.isSymbolicLink(temp)) {
|
||||
ErrorEventFactory.fromThrowable(new IOException("Invalid file type for " + temp)).term().handle();
|
||||
ErrorEventFactory.fromThrowable(new IOException("Invalid file type for " + temp))
|
||||
.term()
|
||||
.handle();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,12 +139,7 @@ public class AppProperties {
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
defaultReleaseDataDir = AppSystemInfo.ofCurrent().getUserHome().resolve(".xpipe");
|
||||
defaultDataDir = AppSystemInfo.ofCurrent()
|
||||
.getUserHome()
|
||||
.resolve(
|
||||
isStaging()
|
||||
? ".xpipe-ptb"
|
||||
: ".xpipe");
|
||||
defaultDataDir = AppSystemInfo.ofCurrent().getUserHome().resolve(isStaging() ? ".xpipe-ptb" : ".xpipe");
|
||||
dataDir = Optional.ofNullable(System.getProperty(AppNames.propertyName("dataDir")))
|
||||
.map(s -> {
|
||||
var p = Path.of(s);
|
||||
|
||||
@@ -5,7 +5,6 @@ import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.util.LinuxLibC;
|
||||
import io.xpipe.app.util.OsType;
|
||||
|
||||
import com.sun.jna.Function;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -49,7 +49,11 @@ public class AppTrayIcon {
|
||||
var quit = new MenuItem(AppI18n.get("quit"));
|
||||
quit.addActionListener(e -> {
|
||||
var closingMenu = new PopupMenu();
|
||||
var mi = new MenuItem(AppI18n.get(DataStorage.get() != null && DataStorage.get().syncEnabled() ? "synchronizingChanges" : "savingChanges") + " ...");
|
||||
var mi = new MenuItem(AppI18n.get(
|
||||
DataStorage.get() != null && DataStorage.get().syncEnabled()
|
||||
? "synchronizingChanges"
|
||||
: "savingChanges")
|
||||
+ " ...");
|
||||
closingMenu.add(mi);
|
||||
trayIcon.setPopupMenu(closingMenu);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.platform.PlatformInit;
|
||||
import io.xpipe.app.platform.PlatformThread;
|
||||
import io.xpipe.app.util.LicenseProvider;
|
||||
import io.xpipe.app.util.OsType;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
|
||||
@@ -105,10 +105,7 @@ public abstract class AppOperationMode {
|
||||
&& ex instanceof StringIndexOutOfBoundsException
|
||||
&& ex.getStackTrace() != null
|
||||
&& Arrays.toString(ex.getStackTrace()).contains("MacAccessible")) {
|
||||
ErrorEventFactory.fromThrowable(ex)
|
||||
.expected()
|
||||
.omit()
|
||||
.handle();
|
||||
ErrorEventFactory.fromThrowable(ex).expected().omit().handle();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.xpipe.app.core.mode;
|
||||
|
||||
import io.xpipe.app.core.AppTray;
|
||||
import io.xpipe.app.core.window.AppMainWindow;
|
||||
import io.xpipe.app.issue.*;
|
||||
import io.xpipe.app.platform.PlatformInit;
|
||||
import io.xpipe.app.platform.PlatformThread;
|
||||
|
||||
@@ -156,7 +156,10 @@ public class AppMainWindow {
|
||||
|
||||
public static synchronized void resetContent() {
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
loadingText.setValue(AppI18n.get(DataStorage.get() != null && DataStorage.get().syncEnabled() ? "synchronizingChanges" : "savingChanges"));
|
||||
loadingText.setValue(AppI18n.get(
|
||||
DataStorage.get() != null && DataStorage.get().syncEnabled()
|
||||
? "synchronizingChanges"
|
||||
: "savingChanges"));
|
||||
loadedContent.setValue(null);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,13 +2,9 @@ package io.xpipe.app.core.window;
|
||||
|
||||
import io.xpipe.app.util.OsType;
|
||||
|
||||
import javafx.geometry.Rectangle2D;
|
||||
import javafx.stage.Screen;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class AppWindowBounds {
|
||||
|
||||
@@ -7,8 +7,6 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.store.DataStore;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
||||
import javafx.application.Platform;
|
||||
|
||||
public abstract class InitHubLeafProvider<T extends DataStore, O> implements HubLeafProvider<T> {
|
||||
|
||||
protected O available;
|
||||
|
||||
@@ -101,37 +101,50 @@ public class StoreCategoryConfigComp extends SimpleRegionBuilder {
|
||||
.addComp(createToggle(sync, parentConfig.getSync()), sync)
|
||||
.disable(syncDisable));
|
||||
if (connectionsCategory) {
|
||||
options.title("connectionConfiguration").sub(new OptionsBuilder()
|
||||
.nameAndDescription("categoryDefaultIdentity")
|
||||
.addComp(new StoreChoiceComp<>(null, identityRef, DataStore.class, null, StoreViewState.get().getAllIdentitiesCategory(),
|
||||
DataStoreCreationCategory.IDENTITY), identityRef)
|
||||
.nameAndDescription("categoryDefaultGateway")
|
||||
.addComp(new StoreChoiceComp<>(null, gatewayRef, DataStore.class, null, StoreViewState.get().getAllConnectionsCategory(),
|
||||
DataStoreCreationCategory.HOST), gatewayRef));
|
||||
options.title("connectionConfiguration")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("categoryDefaultIdentity")
|
||||
.addComp(
|
||||
new StoreChoiceComp<>(
|
||||
null,
|
||||
identityRef,
|
||||
DataStore.class,
|
||||
null,
|
||||
StoreViewState.get().getAllIdentitiesCategory(),
|
||||
DataStoreCreationCategory.IDENTITY),
|
||||
identityRef)
|
||||
.nameAndDescription("categoryDefaultGateway")
|
||||
.addComp(
|
||||
new StoreChoiceComp<>(
|
||||
null,
|
||||
gatewayRef,
|
||||
DataStore.class,
|
||||
null,
|
||||
StoreViewState.get().getAllConnectionsCategory(),
|
||||
DataStoreCreationCategory.HOST),
|
||||
gatewayRef));
|
||||
|
||||
options.title("connectionHandling").sub(new OptionsBuilder().nameAndDescription("categoryDontAllowScripts")
|
||||
.addComp(createToggle(scripts, parentConfig.getDontAllowScripts()), scripts)
|
||||
.nameAndDescription("categoryConfirmAllModifications")
|
||||
.addComp(createToggle(confirm, parentConfig.getConfirmAllModifications()), confirm).nameAndDescription("categoryFreeze")
|
||||
.addComp(createToggle(freeze, parentConfig.getFreezeConfigurations()), freeze));
|
||||
options.title("connectionHandling")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("categoryDontAllowScripts")
|
||||
.addComp(createToggle(scripts, parentConfig.getDontAllowScripts()), scripts)
|
||||
.nameAndDescription("categoryConfirmAllModifications")
|
||||
.addComp(createToggle(confirm, parentConfig.getConfirmAllModifications()), confirm)
|
||||
.nameAndDescription("categoryFreeze")
|
||||
.addComp(createToggle(freeze, parentConfig.getFreezeConfigurations()), freeze));
|
||||
}
|
||||
options
|
||||
.bind(
|
||||
() -> {
|
||||
return new DataStoreCategoryConfig(
|
||||
c.getColor(),
|
||||
scripts.get(),
|
||||
confirm.get(),
|
||||
sync.get(),
|
||||
freeze.get(),
|
||||
identityRef.get() != null
|
||||
? identityRef.get().get().getUuid()
|
||||
: null,
|
||||
gatewayRef.get() != null
|
||||
? gatewayRef.get().get().getUuid()
|
||||
: null);
|
||||
},
|
||||
config);
|
||||
options.bind(
|
||||
() -> {
|
||||
return new DataStoreCategoryConfig(
|
||||
c.getColor(),
|
||||
scripts.get(),
|
||||
confirm.get(),
|
||||
sync.get(),
|
||||
freeze.get(),
|
||||
identityRef.get() != null ? identityRef.get().get().getUuid() : null,
|
||||
gatewayRef.get() != null ? gatewayRef.get().get().getUuid() : null);
|
||||
},
|
||||
config);
|
||||
var r = options.build();
|
||||
r.getStyleClass().add("category-config");
|
||||
var sp = new ScrollPane(r);
|
||||
|
||||
@@ -165,7 +165,9 @@ public class StoreChoicePopover<T extends DataStore> {
|
||||
? new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2p-plus"), () -> {
|
||||
StoreCreationDialog.showCreation(
|
||||
null,
|
||||
DataStoreProvider.byId(creationCategory.getDefaultProvider()).orElseThrow().defaultStore(DataStorage.get().getSelectedCategory()),
|
||||
DataStoreProvider.byId(creationCategory.getDefaultProvider())
|
||||
.orElseThrow()
|
||||
.defaultStore(DataStorage.get().getSelectedCategory()),
|
||||
creationCategory,
|
||||
ignored -> {},
|
||||
false);
|
||||
|
||||
@@ -83,7 +83,6 @@ public class StoreCreationMenu {
|
||||
|
||||
items.add(actionMenu);
|
||||
|
||||
|
||||
if (allowSearch) {
|
||||
var automatically = new MenuItem();
|
||||
automatically.setGraphic(new FontIcon("mdi2e-eye-plus-outline"));
|
||||
@@ -102,10 +101,10 @@ public class StoreCreationMenu {
|
||||
.toList();
|
||||
return 1 == connections.size()
|
||||
&& StoreViewState.get()
|
||||
.getActiveCategory()
|
||||
.getValue()
|
||||
.getRoot()
|
||||
.equals(allCat);
|
||||
.getActiveCategory()
|
||||
.getValue()
|
||||
.getRoot()
|
||||
.equals(allCat);
|
||||
},
|
||||
StoreViewState.get().getAllEntries().getList());
|
||||
automatically.disableProperty().bind(disableSearch);
|
||||
|
||||
@@ -277,9 +277,11 @@ public abstract class StoreEntryComp extends SimpleRegionBuilder {
|
||||
button.style("user-icon");
|
||||
var identity = getWrapper().getEntry().getProvider() != null
|
||||
&& getWrapper().getEntry().getProvider().getCreationCategory() == DataStoreCreationCategory.IDENTITY;
|
||||
var list = getWrapper().getEntry().getAccessScope().getPrincipals().stream().map(p -> "- " + p.getName())
|
||||
var list = getWrapper().getEntry().getAccessScope().getPrincipals().stream()
|
||||
.map(p -> "- " + p.getName())
|
||||
.collect(Collectors.joining("\n"));
|
||||
button.describe(d -> d.name(AppI18n.observable(identity ? "restrictedIdentity" : "restrictedConnection", list)));
|
||||
button.describe(
|
||||
d -> d.name(AppI18n.observable(identity ? "restrictedIdentity" : "restrictedConnection", list)));
|
||||
button.apply(struc -> {
|
||||
AppFontSizes.base(struc);
|
||||
});
|
||||
|
||||
@@ -202,8 +202,8 @@ public class StoreEntryWrapper {
|
||||
.findFirst()
|
||||
.orElse(StoreViewState.get().getAllConnectionsCategory());
|
||||
category.setValue(newCat);
|
||||
accessScopeRestricted.setValue(DataStorageAccessHandler.getInstance().getType() == DataStorageAccessType.ROLE &&
|
||||
entry.getAccessScope().isAccessSubRestricted());
|
||||
accessScopeRestricted.setValue(DataStorageAccessHandler.getInstance().getType() == DataStorageAccessType.ROLE
|
||||
&& entry.getAccessScope().isAccessSubRestricted());
|
||||
pinToTop.setValue(entry.isPinToTop());
|
||||
|
||||
var orderedTags = entry.getTags().stream().sorted().toList();
|
||||
|
||||
@@ -20,7 +20,6 @@ import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Menu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
@@ -63,7 +62,7 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
|
||||
var actionsIncompatible = new SimpleBooleanProperty();
|
||||
var actionsList = DerivedObservableList.<BaseRegionBuilder<?, ?>>arrayList(true);
|
||||
StoreViewState.get().getBatchModeSelection().getList().addListener((ListChangeListener<
|
||||
? super StoreEntryWrapper>)
|
||||
? super StoreEntryWrapper>)
|
||||
c -> {
|
||||
actionsList.getList().clear();
|
||||
var providers = getCompatibleActionProviders();
|
||||
@@ -73,8 +72,9 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
|
||||
|
||||
if (c.getList().size() > 0) {
|
||||
var clazz = c.getList().getFirst().getStore().getValue().getClass();
|
||||
var same = c.getList().stream().allMatch(wrapper ->
|
||||
wrapper.getEntry().getStore().getClass().equals(clazz));
|
||||
var same = c.getList().stream()
|
||||
.allMatch(wrapper ->
|
||||
wrapper.getEntry().getStore().getClass().equals(clazz));
|
||||
actionsIncompatible.set(providers.isEmpty() && !same);
|
||||
actionsEmpty.set(providers.isEmpty() && same);
|
||||
} else {
|
||||
@@ -94,9 +94,15 @@ public class StoreEntryListBatchBarComp extends SimpleRegionBuilder {
|
||||
var actions = new HorizontalComp(actionsList.getList());
|
||||
actions.spacing(2);
|
||||
|
||||
var emptyIndicator = new LabelComp(Bindings.createStringBinding(() -> {
|
||||
return actionsIncompatible.get() ? AppI18n.get("batchActionsIncompatible") : AppI18n.get("batchActionsEmpty");
|
||||
}, actionsEmpty, actionsIncompatible, AppI18n.activeLanguage()));
|
||||
var emptyIndicator = new LabelComp(Bindings.createStringBinding(
|
||||
() -> {
|
||||
return actionsIncompatible.get()
|
||||
? AppI18n.get("batchActionsIncompatible")
|
||||
: AppI18n.get("batchActionsEmpty");
|
||||
},
|
||||
actionsEmpty,
|
||||
actionsIncompatible,
|
||||
AppI18n.activeLanguage()));
|
||||
emptyIndicator.show(actionsIncompatible.or(actionsEmpty));
|
||||
|
||||
var close = new IconButtonComp("mdi2c-close", () -> {
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.xpipe.app.platform.DerivedObservableList;
|
||||
import io.xpipe.app.platform.PlatformThread;
|
||||
import io.xpipe.app.util.GlobalTimer;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableBooleanValue;
|
||||
|
||||
@@ -90,8 +90,8 @@ public class ErrorEventFactory {
|
||||
return t.getMessage();
|
||||
}
|
||||
|
||||
private static synchronized ErrorEvent.ErrorEventBuilder retrieveBuilder(Throwable t) {
|
||||
var b = EVENT_BASES.remove(t);
|
||||
private static synchronized ErrorEvent.ErrorEventBuilder retrieveBuilder(Throwable t) {
|
||||
var b = EVENT_BASES.remove(t);
|
||||
if (b == null) {
|
||||
b = ErrorEvent.builder().throwable(t);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package io.xpipe.app.issue;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.comp.BaseRegionBuilder;
|
||||
import io.xpipe.app.comp.RegionBuilder;
|
||||
import io.xpipe.app.comp.base.*;
|
||||
import io.xpipe.app.core.*;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.Orientation;
|
||||
@@ -15,10 +13,9 @@ import javafx.geometry.Pos;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.*;
|
||||
|
||||
import atlantafx.base.controls.Popover;
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import atlantafx.base.theme.Styles;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class UserReportComp extends ModalOverlayContentComp {
|
||||
|
||||
@@ -19,8 +19,7 @@ public interface Validator {
|
||||
.dependsOn("val", s)
|
||||
.withMethod(c -> {
|
||||
if (c.get("val") == null) {
|
||||
c.error(AppI18n.get(
|
||||
"mustNotBeEmpty", name != null ? name.getValue() : AppI18n.get("value")));
|
||||
c.error(AppI18n.get("mustNotBeEmpty", name != null ? name.getValue() : AppI18n.get("value")));
|
||||
}
|
||||
})
|
||||
.immediate();
|
||||
@@ -33,8 +32,7 @@ public interface Validator {
|
||||
.dependsOn("if", checkIf)
|
||||
.withMethod(c -> {
|
||||
if (Boolean.TRUE.equals(c.get("if")) && c.get("val") == null) {
|
||||
c.error(AppI18n.get(
|
||||
"mustNotBeEmpty", name != null ? name.getValue() : AppI18n.get("value")));
|
||||
c.error(AppI18n.get("mustNotBeEmpty", name != null ? name.getValue() : AppI18n.get("value")));
|
||||
}
|
||||
})
|
||||
.immediate();
|
||||
@@ -45,8 +43,7 @@ public interface Validator {
|
||||
.dependsOn("val", s)
|
||||
.withMethod(c -> {
|
||||
if (((ObservableList<?>) c.get("val")).size() == 0) {
|
||||
c.error(AppI18n.get(
|
||||
"mustNotBeEmpty", name != null ? name.getValue() : AppI18n.get("value")));
|
||||
c.error(AppI18n.get("mustNotBeEmpty", name != null ? name.getValue() : AppI18n.get("value")));
|
||||
}
|
||||
})
|
||||
.immediate();
|
||||
|
||||
@@ -110,10 +110,10 @@ public interface PasswordManager {
|
||||
List<String> urls;
|
||||
|
||||
public boolean matches(String filter) {
|
||||
return title.toLowerCase().contains(filter.toLowerCase()) ||
|
||||
key.toLowerCase().contains(filter.toLowerCase()) ||
|
||||
urls.stream().anyMatch(url -> url.toLowerCase().contains(filter.toLowerCase())) ||
|
||||
(internalId != null && internalId.equalsIgnoreCase(filter));
|
||||
return title.toLowerCase().contains(filter.toLowerCase())
|
||||
|| key.toLowerCase().contains(filter.toLowerCase())
|
||||
|| urls.stream().anyMatch(url -> url.toLowerCase().contains(filter.toLowerCase()))
|
||||
|| (internalId != null && internalId.equalsIgnoreCase(filter));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,18 +143,23 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
|
||||
|
||||
content.getChildren().add(headerBar);
|
||||
|
||||
var box = new ListBoxViewComp<>(shown, all, entry -> {
|
||||
var buttonName = entry.getTitle();
|
||||
var entryButton = new ButtonComp(new ReadOnlyObjectWrapper<>(buttonName), () -> {
|
||||
popover.hide();
|
||||
selectFromList(entry);
|
||||
});
|
||||
entryButton.maxWidth(400);
|
||||
entryButton.style(Styles.FLAT);
|
||||
entryButton.apply(button -> button.setMnemonicParsing(false));
|
||||
entryButton.apply(button -> button.setAlignment(Pos.CENTER_LEFT));
|
||||
return entryButton;
|
||||
}, true);
|
||||
var box = new ListBoxViewComp<>(
|
||||
shown,
|
||||
all,
|
||||
entry -> {
|
||||
var buttonName = entry.getTitle();
|
||||
var entryButton =
|
||||
new ButtonComp(new ReadOnlyObjectWrapper<>(buttonName), () -> {
|
||||
popover.hide();
|
||||
selectFromList(entry);
|
||||
});
|
||||
entryButton.maxWidth(400);
|
||||
entryButton.style(Styles.FLAT);
|
||||
entryButton.apply(button -> button.setMnemonicParsing(false));
|
||||
entryButton.apply(button -> button.setAlignment(Pos.CENTER_LEFT));
|
||||
return entryButton;
|
||||
},
|
||||
true);
|
||||
box.setVisibilityControl(true);
|
||||
box.setFixScrollReset(true);
|
||||
box.prefWidth(400);
|
||||
@@ -163,15 +168,18 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
|
||||
|
||||
var filterString = new SimpleObjectProperty<String>();
|
||||
var footer = new TextFieldComp(filterString);
|
||||
footer.apply(textField -> textField.promptTextProperty().bind(AppI18n.observable("searchFilter")));
|
||||
footer.apply(textField ->
|
||||
textField.promptTextProperty().bind(AppI18n.observable("searchFilter")));
|
||||
content.getChildren().add(footer.build());
|
||||
filterString.addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
var filtered = list.stream().filter(listEntry -> listEntry.matches(newValue)).toList();
|
||||
DerivedObservableList.wrap(shown, true).setContent(filtered);
|
||||
} else {
|
||||
DerivedObservableList.wrap(shown, true).setContent(all);
|
||||
}
|
||||
if (newValue != null) {
|
||||
var filtered = list.stream()
|
||||
.filter(listEntry -> listEntry.matches(newValue))
|
||||
.toList();
|
||||
DerivedObservableList.wrap(shown, true).setContent(filtered);
|
||||
} else {
|
||||
DerivedObservableList.wrap(shown, true).setContent(all);
|
||||
}
|
||||
});
|
||||
|
||||
popover.setContentNode(content);
|
||||
@@ -217,8 +225,8 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
|
||||
testButton.padding(new Insets(6, 9, 6, 9));
|
||||
testButton.disable(BindingsHelper.mapBoolean(value, v -> v == null));
|
||||
|
||||
var testRow = new HorizontalComp(List.of(
|
||||
testButton, new LabelComp(status).apply(struc -> struc.setOpacity(0.8))))
|
||||
var testRow = new HorizontalComp(
|
||||
List.of(testButton, new LabelComp(status).apply(struc -> struc.setOpacity(0.8))))
|
||||
.apply(struc -> struc.setAlignment(Pos.CENTER_LEFT))
|
||||
.apply(struc -> struc.setFillHeight(true));
|
||||
|
||||
|
||||
@@ -52,8 +52,11 @@ public class MultiPrincipalSecret {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<encrypted secret> {\n" + entries.stream().map(entry -> " " + entry.getPrincipal().getName() +
|
||||
": " + entry.getIteration()).collect(Collectors.joining("\n")) + "\n}";
|
||||
return "<encrypted secret> {\n"
|
||||
+ entries.stream()
|
||||
.map(entry -> " " + entry.getPrincipal().getName() + ": " + entry.getIteration())
|
||||
.collect(Collectors.joining("\n"))
|
||||
+ "\n}";
|
||||
}
|
||||
|
||||
public int getMaxIteration() {
|
||||
@@ -73,13 +76,17 @@ public class MultiPrincipalSecret {
|
||||
}
|
||||
|
||||
public boolean isScopeValid() {
|
||||
return entries.stream().allMatch(entry -> !entry.getPrincipal().isAccessible() || entry.getToken().matches(entry.getPrincipal()));
|
||||
return entries.stream()
|
||||
.allMatch(entry ->
|
||||
!entry.getPrincipal().isAccessible() || entry.getToken().matches(entry.getPrincipal()));
|
||||
}
|
||||
|
||||
public boolean supportsScopeEncryption(DataStoreAccessScope scope) {
|
||||
for (EncryptionPrincipal principal : scope.getPrincipals()) {
|
||||
if (!principal.isAccessible()) {
|
||||
var available = entries.stream().filter(entry -> entry.getPrincipal().equals(principal)).findFirst();
|
||||
var available = entries.stream()
|
||||
.filter(entry -> entry.getPrincipal().equals(principal))
|
||||
.findFirst();
|
||||
if (available.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -204,7 +211,10 @@ public class MultiPrincipalSecret {
|
||||
|
||||
l.add(new Entry(
|
||||
principal,
|
||||
keep ? existingEntry.get().getEncrypted() : AesSecretValue.encrypt(secret.getSecret(), principal.getSecretKey()).getEncryptedValue(),
|
||||
keep
|
||||
? existingEntry.get().getEncrypted()
|
||||
: AesSecretValue.encrypt(secret.getSecret(), principal.getSecretKey())
|
||||
.getEncryptedValue(),
|
||||
keep ? iteration : iteration + 1,
|
||||
keep ? existingEntry.get().getToken() : EncryptionToken.of(principal)));
|
||||
} else {
|
||||
|
||||
@@ -70,7 +70,9 @@ public class OptionalEncryptedValue<T> {
|
||||
}
|
||||
|
||||
public OptionalEncryptedValue<T> withUpdatedPrincipals() {
|
||||
return with(value, isEncrypted() ? DataStoreAccessScope.getTargetScope(getSecret().getScope()) : null);
|
||||
return with(
|
||||
value,
|
||||
isEncrypted() ? DataStoreAccessScope.getTargetScope(getSecret().getScope()) : null);
|
||||
}
|
||||
|
||||
public OptionalEncryptedValue<T> with(T value, DataStoreAccessScope scope) {
|
||||
@@ -78,8 +80,8 @@ public class OptionalEncryptedValue<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
var encryptionUnchanged = (secret == null && scope == null) ||
|
||||
(secret != null && scope != null && secret.getScope().equals(scope) && secret.isScopeValid());
|
||||
var encryptionUnchanged = (secret == null && scope == null)
|
||||
|| (secret != null && scope != null && secret.getScope().equals(scope) && secret.isScopeValid());
|
||||
|
||||
// If we don't have a value, we can only restrict the scope further
|
||||
if (value == null) {
|
||||
@@ -110,9 +112,9 @@ public class OptionalEncryptedValue<T> {
|
||||
}
|
||||
|
||||
var s = newValueJson.toPrettyString();
|
||||
var newSecret = secret != null ?
|
||||
secret.with(new InPlaceSecretValue(s.toCharArray()), scope) :
|
||||
MultiPrincipalSecret.of(new InPlaceSecretValue(s.toCharArray()), scope.getPrincipals());
|
||||
var newSecret = secret != null
|
||||
? secret.with(new InPlaceSecretValue(s.toCharArray()), scope)
|
||||
: MultiPrincipalSecret.of(new InPlaceSecretValue(s.toCharArray()), scope.getPrincipals());
|
||||
var hasValue = newSecret.getInternalSecret() != null;
|
||||
return new OptionalEncryptedValue<>(hasValue ? newValueJson : null, hasValue ? value : null, newSecret);
|
||||
}
|
||||
|
||||
@@ -327,15 +327,19 @@ public abstract class DataStorage {
|
||||
|
||||
public boolean refreshStoreEntriesEncryption() {
|
||||
// Update principals of the stores
|
||||
var change = storeEntriesSet.stream().map(dataStoreEntry -> {
|
||||
return dataStoreEntry.refreshStoreEncryption();
|
||||
}).anyMatch(b -> b);
|
||||
var change = storeEntriesSet.stream()
|
||||
.map(dataStoreEntry -> {
|
||||
return dataStoreEntry.refreshStoreEncryption();
|
||||
})
|
||||
.anyMatch(b -> b);
|
||||
|
||||
while (true) {
|
||||
// Update scope for dependent stores if needed, only possible after the first update has been done
|
||||
var followUpChange = storeEntriesSet.stream().map(dataStoreEntry -> {
|
||||
return dataStoreEntry.refreshStoreEncryption();
|
||||
}).anyMatch(b -> b);
|
||||
var followUpChange = storeEntriesSet.stream()
|
||||
.map(dataStoreEntry -> {
|
||||
return dataStoreEntry.refreshStoreEncryption();
|
||||
})
|
||||
.anyMatch(b -> b);
|
||||
if (!followUpChange) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import java.util.regex.Pattern;
|
||||
public class DataStorageQuery {
|
||||
|
||||
public static List<DataStoreEntry> queryUserInput(String input) {
|
||||
var connectionFilter = input != null && !input.isEmpty() && !input.equals("*") && !input.equals("**") ? "**" + input + "**" : "**";
|
||||
var connectionFilter = input != null && !input.isEmpty() && !input.equals("*") && !input.equals("**")
|
||||
? "**" + input + "**"
|
||||
: "**";
|
||||
var found = queryEntry("**", connectionFilter, "*");
|
||||
if (found.size() > 1) {
|
||||
var narrowPath = found.stream()
|
||||
|
||||
@@ -8,7 +8,6 @@ import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@@ -71,7 +70,8 @@ public class DataStoreAccessScope {
|
||||
// A used principal got deleted, reencrypt with encryption key if we have no other access
|
||||
// or just remove the principal if we still have access
|
||||
if (!exists) {
|
||||
var hasOtherSubs = scope.getPrincipals().stream().anyMatch(p -> !p.equals(principal) && p.isSubRestricted());
|
||||
var hasOtherSubs =
|
||||
scope.getPrincipals().stream().anyMatch(p -> !p.equals(principal) && p.isSubRestricted());
|
||||
return hasOtherSubs ? null : encryptPrincipal;
|
||||
}
|
||||
|
||||
|
||||
@@ -529,8 +529,11 @@ public class DataStoreEntry extends DataStorageElement {
|
||||
|
||||
@Override
|
||||
public List<Path> getSyncableFiles() {
|
||||
var list = List.of(directory.resolve("store.json"), directory.resolve("entry.json"),
|
||||
directory.resolve("notes.md"), directory.resolve("notes.json"));
|
||||
var list = List.of(
|
||||
directory.resolve("store.json"),
|
||||
directory.resolve("entry.json"),
|
||||
directory.resolve("notes.md"),
|
||||
directory.resolve("notes.json"));
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -599,7 +602,8 @@ public class DataStoreEntry extends DataStorageElement {
|
||||
this.notesNode = this.notesNode != null ? this.notesNode.prepareForWrite(this, true, getNotes()) : null;
|
||||
if (this.notesNode != null && this.notesNode.requiresWrite()) {
|
||||
var file = this.notesNode.isEncrypted() ? encryptedNotesFile : normalNotesFile;
|
||||
Files.writeString(file, this.notesNode.isEncrypted() ? this.notesNode.getWriteString() : this.notesNode.getValue());
|
||||
Files.writeString(
|
||||
file, this.notesNode.isEncrypted() ? this.notesNode.getWriteString() : this.notesNode.getValue());
|
||||
}
|
||||
|
||||
this.storeNode = this.storeNode.prepareForWrite(this, true, getStore());
|
||||
@@ -708,7 +712,8 @@ public class DataStoreEntry extends DataStorageElement {
|
||||
return false;
|
||||
}
|
||||
|
||||
var newNode = storeNode.prepareForWrite(this, true, getStore() instanceof EncryptionStore s ? s.withUpdatedPrincipals() : getStore());
|
||||
var newNode = storeNode.prepareForWrite(
|
||||
this, true, getStore() instanceof EncryptionStore s ? s.withUpdatedPrincipals() : getStore());
|
||||
if (!newNode.equals(storeNode)) {
|
||||
storeNode = newNode;
|
||||
dirty = newNode.requiresWrite();
|
||||
|
||||
@@ -52,7 +52,8 @@ public class DataStoreEntryNode<T> {
|
||||
var targetScope = DataStoreAccessScope.getTargetScope(entry.getAccessScope());
|
||||
var currentScope = enc.getSecret() != null ? enc.getSecret().getScope() : targetScope;
|
||||
|
||||
var shouldEncrypt = (encryptIfRestricted && targetScope.isAccessSubRestricted()) || AppPrefs.get().encryptAllVaultData().get();
|
||||
var shouldEncrypt = (encryptIfRestricted && targetScope.isAccessSubRestricted())
|
||||
|| AppPrefs.get().encryptAllVaultData().get();
|
||||
if (shouldEncrypt) {
|
||||
var supported = enc.supportsScopeEncryption(targetScope);
|
||||
if (!supported) {
|
||||
@@ -61,7 +62,7 @@ public class DataStoreEntryNode<T> {
|
||||
}
|
||||
|
||||
var encryptionChange = shouldEncrypt && !enc.isEncrypted() || !shouldEncrypt && enc.isEncrypted();
|
||||
var scopeTargetChange = !targetScope.equals(currentScope)|| !enc.isScopeValid();
|
||||
var scopeTargetChange = !targetScope.equals(currentScope) || !enc.isScopeValid();
|
||||
var valueChange = !Objects.equals(getValue(), newValue);
|
||||
if (encryptionChange || valueChange || scopeTargetChange) {
|
||||
var newEnc = enc.with(newValue, shouldEncrypt ? targetScope : null);
|
||||
|
||||
@@ -488,25 +488,20 @@ public class StandardStorage extends DataStorage {
|
||||
}
|
||||
});
|
||||
|
||||
storeEntriesSet
|
||||
.forEach(e -> {
|
||||
try {
|
||||
synchronized (dir) {
|
||||
var exists = Files.exists(e.getDirectory());
|
||||
var dirty = e.isDirty();
|
||||
e.writeDataToDisk();
|
||||
dataStorageSyncHandler.handleEntry(e, exists, dirty);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Data corruption and schema changes are expected
|
||||
exception.set(ex);
|
||||
ErrorEventFactory.fromThrowable(ex)
|
||||
.expected()
|
||||
.omit()
|
||||
.build()
|
||||
.handle();
|
||||
}
|
||||
});
|
||||
storeEntriesSet.forEach(e -> {
|
||||
try {
|
||||
synchronized (dir) {
|
||||
var exists = Files.exists(e.getDirectory());
|
||||
var dirty = e.isDirty();
|
||||
e.writeDataToDisk();
|
||||
dataStorageSyncHandler.handleEntry(e, exists, dirty);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Data corruption and schema changes are expected
|
||||
exception.set(ex);
|
||||
ErrorEventFactory.fromThrowable(ex).expected().omit().build().handle();
|
||||
}
|
||||
});
|
||||
|
||||
// Show one exception
|
||||
if (exception.get() != null) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.xpipe.app.store;
|
||||
|
||||
public interface EncryptionStore extends DataStore{
|
||||
public interface EncryptionStore extends DataStore {
|
||||
|
||||
DataStore withUpdatedPrincipals();
|
||||
}
|
||||
@@ -14,7 +14,8 @@ import java.util.List;
|
||||
|
||||
@JsonTypeName("local")
|
||||
@Value
|
||||
public class LocalStore implements NetworkTunnelStore, ShellStore, StatefulDataStore<ShellStoreState>, AccessScopeStore {
|
||||
public class LocalStore
|
||||
implements NetworkTunnelStore, ShellStore, StatefulDataStore<ShellStoreState>, AccessScopeStore {
|
||||
|
||||
@Override
|
||||
public Class<ShellStoreState> getStateClass() {
|
||||
|
||||
@@ -430,7 +430,8 @@ public class AppJacksonModule extends SimpleModule {
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static class OptionalEncryptedValueDeserializer<T extends OptionalEncryptedValue<?>> extends ValueDeserializer<T> {
|
||||
public static class OptionalEncryptedValueDeserializer<T extends OptionalEncryptedValue<?>>
|
||||
extends ValueDeserializer<T> {
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
|
||||
@@ -35,7 +35,10 @@ public class FileOpener {
|
||||
try {
|
||||
path = path.toRealPath();
|
||||
} catch (IOException e) {
|
||||
ErrorEventFactory.fromThrowable(e).description("Unable to resolve link").expected().handle();
|
||||
ErrorEventFactory.fromThrowable(e)
|
||||
.description("Unable to resolve link")
|
||||
.expected()
|
||||
.handle();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.xpipe.app.ext.ModuleLayerLoader;
|
||||
import io.xpipe.app.store.DataStoreProvider;
|
||||
|
||||
@@ -17,7 +16,6 @@ import tools.jackson.databind.json.JsonMapper;
|
||||
import tools.jackson.databind.jsontype.TypeSerializer;
|
||||
import tools.jackson.databind.module.SimpleModule;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -23,7 +24,7 @@ public class LinuxLibC {
|
||||
try {
|
||||
LibC libc = Native.load("c", LibC.class);
|
||||
return Optional.of((library = libc));
|
||||
} catch (Throwable t) {
|
||||
} catch (Throwable t) {
|
||||
ErrorEventFactory.fromThrowable(t).handle();
|
||||
loadingFailed = true;
|
||||
return Optional.empty();
|
||||
@@ -37,4 +38,3 @@ public class LinuxLibC {
|
||||
int setsid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.xpipe.app.webtop;
|
||||
|
||||
import io.xpipe.app.core.AppDisplayScale;
|
||||
import io.xpipe.app.core.AppRestart;
|
||||
import io.xpipe.app.core.mode.AppOperationMode;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
name=lombok
|
||||
version=1.18.46
|
||||
version=1.18.48
|
||||
license=MIT License
|
||||
link=https://projectlombok.org/
|
||||
@@ -79,9 +79,14 @@ public interface IdentityValue {
|
||||
static IdentityValue.InPlace of(String user, SecretRetrievalStrategy password, SshIdentityStrategy sshIdentity) {
|
||||
var s = LocalIdentityStore.builder()
|
||||
.username(user)
|
||||
.password(password != null ? OptionalEncryptedValue.of(password, DataStoreAccessScope.encryption()) : null)
|
||||
.password(
|
||||
password != null
|
||||
? OptionalEncryptedValue.of(password, DataStoreAccessScope.encryption())
|
||||
: null)
|
||||
.sshIdentity(
|
||||
sshIdentity != null ? OptionalEncryptedValue.of(sshIdentity, DataStoreAccessScope.encryption()) : null)
|
||||
sshIdentity != null
|
||||
? OptionalEncryptedValue.of(sshIdentity, DataStoreAccessScope.encryption())
|
||||
: null)
|
||||
.build();
|
||||
return of(s);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,8 @@ import io.xpipe.app.secret.SecretNoneStrategy;
|
||||
import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.storage.DataStoreAccessScope;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.store.AccessScopeStore;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.app.store.EncryptionStore;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
@@ -37,9 +35,9 @@ public class LocalIdentityStore extends IdentityStore {
|
||||
if (!(o instanceof LocalIdentityStore that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(username, that.username) &&
|
||||
Objects.equals(password, that.password) &&
|
||||
Objects.equals(sshIdentity, that.sshIdentity);
|
||||
return Objects.equals(username, that.username)
|
||||
&& Objects.equals(password, that.password)
|
||||
&& Objects.equals(sshIdentity, that.sshIdentity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,9 +7,7 @@ import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreAccessScope;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.store.AccessScopeStore;
|
||||
import io.xpipe.app.store.DataStore;
|
||||
import io.xpipe.app.store.EncryptionStore;
|
||||
import io.xpipe.app.store.StatefulDataStore;
|
||||
import io.xpipe.app.util.ValidationException;
|
||||
import io.xpipe.app.util.Validators;
|
||||
@@ -31,8 +29,7 @@ import java.util.UUID;
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class MultiIdentityStore extends IdentityStore
|
||||
implements StatefulDataStore<MultiIdentityStoreState> {
|
||||
public class MultiIdentityStore extends IdentityStore implements StatefulDataStore<MultiIdentityStoreState> {
|
||||
|
||||
public static boolean isExclusivelyHeld(DataStoreEntryRef<IdentityStore> ref) {
|
||||
return getExclusiveHolder(ref).isPresent();
|
||||
|
||||
@@ -9,9 +9,7 @@ import io.xpipe.app.secret.SecretNoneStrategy;
|
||||
import io.xpipe.app.secret.SecretRetrievalStrategy;
|
||||
import io.xpipe.app.storage.DataStoreAccessScope;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.store.AccessScopeStore;
|
||||
import io.xpipe.app.store.DataStore;
|
||||
import io.xpipe.app.store.EncryptionStore;
|
||||
import io.xpipe.app.util.ValidationException;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
@@ -41,10 +39,10 @@ public class SyncedIdentityStore extends IdentityStore {
|
||||
if (!(o instanceof SyncedIdentityStore that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(username, that.username) &&
|
||||
Objects.equals(password, that.password) &&
|
||||
Objects.equals(sshIdentity, that.sshIdentity) &&
|
||||
Objects.equals(accessScope, that.accessScope);
|
||||
return Objects.equals(username, that.username)
|
||||
&& Objects.equals(password, that.password)
|
||||
&& Objects.equals(sshIdentity, that.sshIdentity)
|
||||
&& Objects.equals(accessScope, that.accessScope);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,7 +40,7 @@ public class IncusContainerStore
|
||||
PauseableStore,
|
||||
NameableStore,
|
||||
HostAddressGatewayStore,
|
||||
EncryptionStore{
|
||||
EncryptionStore {
|
||||
|
||||
DataStoreEntryRef<IncusInstallStore> install;
|
||||
String projectName;
|
||||
@@ -49,8 +49,11 @@ public class IncusContainerStore
|
||||
|
||||
@Override
|
||||
public DataStore withUpdatedPrincipals() {
|
||||
return toBuilder().identity(identity != null ? identity.withUpdatedPrincipals() : null).build();
|
||||
return toBuilder()
|
||||
.identity(identity != null ? identity.withUpdatedPrincipals() : null)
|
||||
.build();
|
||||
}
|
||||
|
||||
public IncusCommandView.Project view() throws Exception {
|
||||
return view(getInstall().getStore().getHost().getStore().getOrStartSession());
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class LxdContainerStore
|
||||
PauseableStore,
|
||||
NameableStore,
|
||||
HostAddressGatewayStore,
|
||||
EncryptionStore{
|
||||
EncryptionStore {
|
||||
|
||||
DataStoreEntryRef<LxdCmdStore> cmd;
|
||||
String projectName;
|
||||
@@ -49,8 +49,11 @@ public class LxdContainerStore
|
||||
|
||||
@Override
|
||||
public DataStore withUpdatedPrincipals() {
|
||||
return toBuilder().identity(identity != null ? identity.withUpdatedPrincipals() : null).build();
|
||||
return toBuilder()
|
||||
.identity(identity != null ? identity.withUpdatedPrincipals() : null)
|
||||
.build();
|
||||
}
|
||||
|
||||
public LxdCommandView.Project view() throws Exception {
|
||||
return view(getCmd().getStore().getHost().getStore().getOrStartSession());
|
||||
}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
dependencies {
|
||||
compileOnly 'org.projectlombok:lombok:edge-SNAPSHOT'
|
||||
annotationProcessor 'org.projectlombok:lombok:edge-SNAPSHOT'
|
||||
testCompileOnly 'org.projectlombok:lombok:edge-SNAPSHOT'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok:edge-SNAPSHOT'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.48'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.48'
|
||||
testCompileOnly 'org.projectlombok:lombok:1.18.48'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok:1.18.48'
|
||||
}
|
||||
|
||||
testing {
|
||||
suites {
|
||||
configureEach {
|
||||
dependencies {
|
||||
compileOnly 'org.projectlombok:lombok:edge-SNAPSHOT'
|
||||
annotationProcessor 'org.projectlombok:lombok:edge-SNAPSHOT'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.48'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.48'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://projectlombok.org/edge-releases' }
|
||||
}
|
||||
Generated
+1
@@ -757,6 +757,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Brugerdefineret PKCS#11-bibliotek
|
||||
sshAgent=OpenSSH-agent
|
||||
none=Ingen
|
||||
empty=Tom
|
||||
index=Indeks ...
|
||||
otherExternal=Anden ekstern godkendelse
|
||||
sync=Synkronisering
|
||||
|
||||
Generated
+1
@@ -767,6 +767,7 @@ customPkcs11Library=Benutzerdefinierte PKCS#11-Bibliothek
|
||||
sshAgent=OpenSSH-Agent
|
||||
#custom
|
||||
none=Nichts
|
||||
empty=Leer
|
||||
index=Inhaltsverzeichnis ...
|
||||
otherExternal=Andere externe Authentifizierung
|
||||
sync=Synchronisieren
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Biblioteca PKCS#11 personalizada
|
||||
sshAgent=Agente de OpenSSH
|
||||
none=Ninguno
|
||||
empty=Vacío
|
||||
index=Índice...
|
||||
otherExternal=Otras formas de autenticación externa
|
||||
sync=Sincronizar
|
||||
|
||||
Generated
+1
@@ -761,6 +761,7 @@ gpgAgent=Agent GPG
|
||||
customPkcs11Library=Bibliothèque PKCS#11 personnalisée
|
||||
sshAgent=Agent OpenSSH
|
||||
none=Aucun
|
||||
empty=Vide
|
||||
index=Index...
|
||||
otherExternal=Autres méthodes d'authentification externes
|
||||
sync=Synchronisation
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=Agen GPG
|
||||
customPkcs11Library=Pustaka PKCS#11 khusus
|
||||
sshAgent=Agen OpenSSH
|
||||
none=Tidak ada
|
||||
empty=Kosong
|
||||
index=Indeks ...
|
||||
otherExternal=Otentikasi eksternal lainnya
|
||||
sync=Sinkronisasi
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Libreria PKCS#11 personalizzata
|
||||
sshAgent=Agente OpenSSH
|
||||
none=Nessuno
|
||||
empty=Vuoto
|
||||
index=Indice ...
|
||||
otherExternal=Altre modalità di autenticazione esterna
|
||||
sync=Sincronizzazione
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPGエージェント
|
||||
customPkcs11Library=カスタムPKCS#11ライブラリ
|
||||
sshAgent=OpenSSHエージェント
|
||||
none=なし
|
||||
empty=空
|
||||
index=目次 ...
|
||||
otherExternal=その他の外部認証
|
||||
sync=同期
|
||||
|
||||
Generated
+1
@@ -765,6 +765,7 @@ gpgAgent=GPG 에이전트
|
||||
customPkcs11Library=사용자 정의 PKCS#11 라이브러리
|
||||
sshAgent=OpenSSH 에이전트
|
||||
none=없음
|
||||
empty=비어 있음
|
||||
index=목차 ...
|
||||
otherExternal=기타 외부 인증
|
||||
sync=동기화
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Aangepaste PKCS#11-bibliotheek
|
||||
sshAgent=OpenSSH-agent
|
||||
none=Geen
|
||||
empty=Leeg
|
||||
index=Index ...
|
||||
otherExternal=Andere externe authenticatie
|
||||
sync=Synchroniseren
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Niestandardowa biblioteka PKCS#11
|
||||
sshAgent=Agent OpenSSH
|
||||
none=Brak
|
||||
empty=Puste
|
||||
index=Spis treści ...
|
||||
otherExternal=Inne metody uwierzytelniania zewnętrznego
|
||||
sync=Synchronizacja
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Biblioteca PKCS#11 personalizada
|
||||
sshAgent=Agente OpenSSH
|
||||
none=Nenhum
|
||||
empty=Vazio
|
||||
index=Índice ...
|
||||
otherExternal=Outras formas de autenticação externa
|
||||
sync=Sincronizar
|
||||
|
||||
Generated
+1
@@ -807,6 +807,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Пользовательская библиотека PKCS#11
|
||||
sshAgent=Агент OpenSSH
|
||||
none=Нет
|
||||
empty=Пусто
|
||||
index=Указатель ...
|
||||
otherExternal=Другие способы внешней аутентификации
|
||||
sync=Синхронизация
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Anpassat PKCS#11-bibliotek
|
||||
sshAgent=OpenSSH-agent
|
||||
none=Ingen
|
||||
empty=Tom
|
||||
index=Index ...
|
||||
otherExternal=Annan extern autentisering
|
||||
sync=Synkronisering
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Aracısı
|
||||
customPkcs11Library=Özel PKCS#11 kütüphanesi
|
||||
sshAgent=OpenSSH ajanı
|
||||
none=Yok
|
||||
empty=Boş
|
||||
index=İçindekiler ...
|
||||
otherExternal=Diğer harici kimlik doğrulama yöntemleri
|
||||
sync=Senkronizasyon
|
||||
|
||||
Generated
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=Thư viện PKCS#11 tùy chỉnh
|
||||
sshAgent=Trình đại lý OpenSSH
|
||||
none=Không có
|
||||
empty=Trống
|
||||
index=Mục lục ...
|
||||
otherExternal=Các phương thức xác thực bên ngoài khác
|
||||
sync=Đồng bộ hóa
|
||||
|
||||
+1
@@ -1023,6 +1023,7 @@ customPkcs11Library=自定义 PKCS#11 库
|
||||
#custom
|
||||
sshAgent=OpenSSH Agent
|
||||
none=无
|
||||
empty=空
|
||||
#custom
|
||||
index=自定义顺序
|
||||
#custom
|
||||
|
||||
+1
@@ -741,6 +741,7 @@ gpgAgent=GPG Agent
|
||||
customPkcs11Library=自訂 PKCS#11 函式庫
|
||||
sshAgent=OpenSSH 代理程式
|
||||
none=無
|
||||
empty=空白
|
||||
index=目錄 ...
|
||||
otherExternal=其他外部驗證
|
||||
sync=同步
|
||||
|
||||
Reference in new issue
Block a user