mirror of
https://github.com/xpipe-io/xpipe.git
synced 2025-04-17 09:43:37 +00:00
Various fixes
This commit is contained in:
parent
de1daa3e02
commit
d46228911f
9 changed files with 84 additions and 31 deletions
|
@ -350,7 +350,7 @@ public class BrowserFileTransferOperation {
|
|||
}
|
||||
|
||||
outputStream = target.getFileSystem().openOutput(targetFile, fileSize);
|
||||
transferFile(sourceFile, inputStream, outputStream, transferred, totalSize, start);
|
||||
transferFile(sourceFile, inputStream, outputStream, transferred, totalSize, start, fileSize);
|
||||
inputStream.transferTo(OutputStream.nullOutputStream());
|
||||
} catch (Exception ex) {
|
||||
// Mark progress as finished to reset any progress display
|
||||
|
@ -409,7 +409,8 @@ public class BrowserFileTransferOperation {
|
|||
OutputStream outputStream,
|
||||
AtomicLong transferred,
|
||||
AtomicLong total,
|
||||
Instant start)
|
||||
Instant start,
|
||||
long expectedFileSize)
|
||||
throws Exception {
|
||||
// Initialize progress immediately prior to reading anything
|
||||
updateProgress(new BrowserTransferProgress(sourceFile.getName(), transferred.get(), total.get(), start));
|
||||
|
@ -418,6 +419,7 @@ public class BrowserFileTransferOperation {
|
|||
var exception = new AtomicReference<Exception>();
|
||||
var thread = ThreadHelper.createPlatformThread("transfer", true, () -> {
|
||||
try {
|
||||
long readCount = 0;
|
||||
var bs = (int) Math.min(DEFAULT_BUFFER_SIZE, sourceFile.getSize());
|
||||
byte[] buffer = new byte[bs];
|
||||
int read;
|
||||
|
@ -434,11 +436,17 @@ public class BrowserFileTransferOperation {
|
|||
|
||||
outputStream.write(buffer, 0, read);
|
||||
transferred.addAndGet(read);
|
||||
updateProgress(
|
||||
new BrowserTransferProgress(sourceFile.getName(), transferred.get(), total.get(), start));
|
||||
readCount += read;
|
||||
updateProgress(new BrowserTransferProgress(sourceFile.getName(), transferred.get(), total.get(), start));
|
||||
}
|
||||
|
||||
var incomplete = readCount < expectedFileSize;
|
||||
if (incomplete) {
|
||||
throw new IOException("Source file " + sourceFile.getPath() + " input did end prematurely");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
exception.set(ex);
|
||||
killStreams.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.xpipe.app.util.Hyperlinks;
|
|||
import io.xpipe.app.util.LabelGraphic;
|
||||
import io.xpipe.app.util.LicenseProvider;
|
||||
|
||||
import io.xpipe.app.util.PlatformThread;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
@ -66,19 +67,27 @@ public class AppLayoutModel {
|
|||
}
|
||||
|
||||
public void selectBrowser() {
|
||||
selected.setValue(entries.get(1));
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
selected.setValue(entries.get(1));
|
||||
});
|
||||
}
|
||||
|
||||
public void selectSettings() {
|
||||
selected.setValue(entries.get(2));
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
selected.setValue(entries.get(2));
|
||||
});
|
||||
}
|
||||
|
||||
public void selectLicense() {
|
||||
selected.setValue(entries.get(3));
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
selected.setValue(entries.get(3));
|
||||
});
|
||||
}
|
||||
|
||||
public void selectConnections() {
|
||||
selected.setValue(entries.getFirst());
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
selected.setValue(entries.getFirst());
|
||||
});
|
||||
}
|
||||
|
||||
private List<Entry> createEntryList() {
|
||||
|
|
|
@ -13,6 +13,8 @@ import io.xpipe.app.util.WindowsRegistry;
|
|||
import io.xpipe.core.process.OsType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
|
@ -72,13 +74,12 @@ public class TermiusTerminalType implements ExternalTerminalType {
|
|||
return;
|
||||
}
|
||||
|
||||
var host = "localhost";
|
||||
var b = SshLocalBridge.get();
|
||||
var host = b.getHost();
|
||||
var port = b.getPort();
|
||||
var user = b.getUser();
|
||||
var name = b.getIdentityKey().getFileName().toString();
|
||||
Hyperlinks.open("termius://app/host-sharing#label=" + name + "&ip=" + host + "&port=" + port + "&username="
|
||||
+ user + "&os=undefined");
|
||||
var user = URLEncoder.encode(b.getUser(), StandardCharsets.UTF_8);
|
||||
var name = b.getName();
|
||||
Hyperlinks.open("termius://app/host-sharing#label=" + name + "&ip=" + host + "&port=" + port + "&username=" + user + "&os=undefined");
|
||||
}
|
||||
|
||||
private boolean showInfo() throws IOException {
|
||||
|
@ -91,7 +92,7 @@ public class TermiusTerminalType implements ExternalTerminalType {
|
|||
var keyContent = Files.readString(b.getIdentityKey());
|
||||
var activated =
|
||||
AppI18n.get().getMarkdownDocumentation("app:termiusSetup").formatted(b.getIdentityKey(), keyContent);
|
||||
var modal = ModalOverlay.of("termiusSetup", new MarkdownComp(activated, s -> s, false).prefWidth(450));
|
||||
var modal = ModalOverlay.of("termiusSetup", new MarkdownComp(activated, s -> s, false).prefWidth(550));
|
||||
modal.addButton(ModalButton.ok(() -> {
|
||||
AppCache.update("termiusSetup", true);
|
||||
}));
|
||||
|
|
|
@ -111,7 +111,7 @@ public class SecretRetrievalStrategyHelper {
|
|||
}
|
||||
map.put(AppI18n.observable("app.prompt"), new OptionsBuilder());
|
||||
map.put(AppI18n.observable("app.password"), inPlace(inPlace));
|
||||
map.put(AppI18n.observable("app.passwordManager"), passwordManager(passwordManager));
|
||||
map.put(AppI18n.observable("app.externalPasswordManager"), passwordManager(passwordManager));
|
||||
map.put(AppI18n.observable("app.customCommand"), customCommand(customCommand));
|
||||
|
||||
int offset = allowNone ? 0 : -1;
|
||||
|
|
|
@ -16,7 +16,9 @@ import lombok.Setter;
|
|||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
public class SshLocalBridge {
|
||||
|
@ -40,10 +42,14 @@ public class SshLocalBridge {
|
|||
this.user = user;
|
||||
}
|
||||
|
||||
private String getName() {
|
||||
public String getName() {
|
||||
return AppProperties.get().isStaging() ? "xpipe_ptb_bridge" : "xpipe_bridge";
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
public Path getPubHostKey() {
|
||||
return directory.resolve(getName() + "_host_key.pub");
|
||||
}
|
||||
|
@ -150,7 +156,8 @@ public class SshLocalBridge {
|
|||
INSTANCE.getPubIdentityKey());
|
||||
Files.writeString(config, content);
|
||||
|
||||
// INSTANCE.updateConfig();
|
||||
// Write to local SSH client config
|
||||
INSTANCE.updateConfig();
|
||||
|
||||
var exec = getSshd(sc);
|
||||
var launchCommand = CommandBuilder.of()
|
||||
|
@ -178,25 +185,42 @@ public class SshLocalBridge {
|
|||
}
|
||||
|
||||
private void updateConfig() throws IOException {
|
||||
var hostEntry = """
|
||||
Host %s
|
||||
HostName localhost
|
||||
User "%s"
|
||||
Port %s
|
||||
IdentityFile "%s"
|
||||
"""
|
||||
.formatted(getName(), user, port, getIdentityKey());
|
||||
|
||||
var file = Path.of(System.getProperty("user.home"), ".ssh", "config");
|
||||
if (!Files.exists(file)) {
|
||||
Files.writeString(file, hostEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
var content = Files.readString(file);
|
||||
if (content.contains(getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var updated = content + "\n\n"
|
||||
+ """
|
||||
var content = Files.readString(file).lines().collect(Collectors.joining("\n")) + "\n";
|
||||
var pattern = Pattern.compile("""
|
||||
Host %s
|
||||
HostName localhost
|
||||
User "%s"
|
||||
Port %s
|
||||
IdentityFile "%s"
|
||||
"""
|
||||
.formatted(getName(), port, user, getIdentityKey());
|
||||
{4}HostName localhost
|
||||
{4}User "(.+)"
|
||||
{4}Port (\\d+)
|
||||
{4}IdentityFile "(.+)"
|
||||
""".formatted(getName()));
|
||||
var matcher = pattern.matcher(content);
|
||||
if (matcher.find()) {
|
||||
var replaced = matcher.replaceFirst(Matcher.quoteReplacement(hostEntry));
|
||||
Files.writeString(file, replaced);
|
||||
return;
|
||||
}
|
||||
|
||||
// Probably an invalid entry that did not match
|
||||
if (content.contains("Host " + getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var updated = content + "\n" + hostEntry + "\n";
|
||||
Files.writeString(file, updated);
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ public class CommandBuilder {
|
|||
}
|
||||
|
||||
public CommandBuilder addFile(FilePath s) {
|
||||
return addFile(s.toString());
|
||||
return addFile(s != null ? s.toString() : null);
|
||||
}
|
||||
|
||||
public CommandBuilder addLiteral(String s) {
|
||||
|
|
3
dist/changelogs/16.0.md
vendored
3
dist/changelogs/16.0.md
vendored
|
@ -26,10 +26,12 @@ The password manager integration has been improved and made more robust:
|
|||
## Other
|
||||
|
||||
- The SSH gateway implementation has been reworked so that you can now use local SSH keys and other identities for connections with gateways
|
||||
- Generated connection names, e.g. VM names, will now automatically update on refresh when they were changed
|
||||
- Various speed improvements for shell operations
|
||||
- Various startup speed improvements
|
||||
- The scripts context menu now shows the respective scripts icons instead of generic ones
|
||||
- There is now built-in support to refresh an SSO openpubkey with the opkssh tool when needed
|
||||
- When the SSH password is set to none, XPipe will no longer prompt for it anyway if the preferred auth failed
|
||||
- The Windows application will now block the shutdown until save/sync has finished, preventing vault corruption caused by a sudden shutdown
|
||||
- Add setting to disable HTTPs TLS verification for license activation API calls for cases where TLS traffic is decrypted in your organization
|
||||
|
||||
|
@ -41,3 +43,4 @@ The password manager integration has been improved and made more robust:
|
|||
- Fix application restart after update not applying current workspace directory
|
||||
- Fix custom service commands not launching properly with PowerShell as the local shell
|
||||
- Fix update check being influenced by the local GitHub rate limiting
|
||||
- Fix repeated file browser errors when remote system did not have the stat command
|
||||
|
|
|
@ -196,6 +196,13 @@ public interface SshIdentityStrategy {
|
|||
+ " is in non-standard PuTTY Private Key format (.ppk), which is not supported by OpenSSH. Please export/convert it to a standard format like .pem via PuTTY"));
|
||||
}
|
||||
|
||||
if (resolved.endsWith(".pub")) {
|
||||
throw ErrorEvent.expected(
|
||||
new IllegalArgumentException(
|
||||
"Identity file " + resolved
|
||||
+ " is marked to be a public key file, SSH authentication requires the private key"));
|
||||
}
|
||||
|
||||
if ((parent.getOsType().equals(OsType.LINUX) || parent.getOsType().equals(OsType.MACOS))) {
|
||||
// Try to preserve the same permission set
|
||||
parent.command(CommandBuilder.of()
|
||||
|
|
1
lang/strings/translations_en.properties
generated
1
lang/strings/translations_en.properties
generated
|
@ -352,6 +352,7 @@ developerModeDescription=When enabled, you will have access to a variety of addi
|
|||
editor=Editor
|
||||
custom=Custom
|
||||
passwordManager=Password manager
|
||||
externalPasswordManager=External password manager
|
||||
passwordManagerDescription=The password manager implementation to execute to fetch passwords.\n\nYou can then set the key to be retrieved whenever you set up a connection which requires a password.
|
||||
passwordManagerCommandTest=Test password manager
|
||||
passwordManagerCommandTestDescription=You can test here whether the output looks correct if you have set up a password manager command. The command should only output the password itself to stdout, no other formatting should be included in the output.
|
||||
|
|
Loading…
Add table
Reference in a new issue