Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
subhra74 committed Mar 30, 2024
1 parent 82b2f1d commit 2134d5d
Show file tree
Hide file tree
Showing 23 changed files with 1,635 additions and 61 deletions.
21 changes: 21 additions & 0 deletions app/notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
* sftp-server(8): add a "users-groups-by-id@openssh.com" extension
request that allows the client to obtain user/group names that
correspond to a set of uids/gids.

* sftp(1): use "users-groups-by-id@openssh.com" sftp-server
extension (when available) to fill in user/group names for
directory listings.

* sftp-server(8): support the "home-directory" extension request
defined in draft-ietf-secsh-filexfer-extensions-00. This overlaps
a bit with the existing "expand-path@openssh.com", but some other
clients support it.

/usr/libexec/sftp-server
"expand-path@openssh.com"
https://bugzilla.mindrot.org/show_bug.cgi?id=2948
limits@openssh.com
lsetstat@openssh.com
https://www.openssh.com/releasenotes.html
https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-extensions-00
https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
8 changes: 8 additions & 0 deletions app/src/main/java/muon/dto/session/SessionInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class SessionInfo extends NamedItem {
private transient String osName;
private transient String osType;
private transient Boolean shellAccess;
private transient boolean loginAsSudo;

public int getAuthMode() {
return authMode;
Expand Down Expand Up @@ -356,4 +357,11 @@ public void setShellAccess(Boolean shellAccess) {
this.shellAccess = shellAccess;
}

public boolean isLoginAsSudo() {
return loginAsSudo;
}

public void setLoginAsSudo(boolean loginAsSudo) {
this.loginAsSudo = loginAsSudo;
}
}
6 changes: 4 additions & 2 deletions app/src/main/java/muon/misc/ExtendedRemoteDirectory.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
*/
package muon.misc;


import muon.ssh.RemoteDirectory;
import muon.ssh.SFTPEngine;
import net.schmizz.sshj.sftp.*;
import net.schmizz.sshj.sftp.Response.StatusCode;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -59,7 +61,7 @@ public List<RemoteResourceInfoWrapper> scanExtended(
break;

case STATUS:
res.ensureStatusIs(StatusCode.EOF);
res.ensureStatusIs(Response.StatusCode.EOF);
break loop;

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,6 @@ public Component getTableCellRendererComponent(JTable table,
public int calculateRowHeight() {
iconLbl.setIcon(folderIcon);
label1.setText("some text");
return p1.getPreferredSize().height;
return Math.max(p1.getPreferredSize().height, 30);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void newOrRename(Action action) {
if (retryWithSudo.get()) {
var ret = SudoUtils.exec(fileBrowserView.getSessionInfo(), String.format("mv -f '%s' '%s'",
fileBrowserView.getSelectedFiles().get(0).getPath(),
PathUtils.combineUnix(fileBrowserView.getPath(), finalFileName)), AppUtils::getPassword);
PathUtils.combineUnix(fileBrowserView.getPath(), finalFileName)), AppUtils::getPassword, cancellationToken);
if (ret != 0) {
throw new Exception("Operation failed");
}
Expand All @@ -92,7 +92,7 @@ public void newOrRename(Action action) {
case NewFile:
if (retryWithSudo.get()) {
var ret = SudoUtils.exec(fileBrowserView.getSessionInfo(), String.format("touch '%s'",
PathUtils.combineUnix(fileBrowserView.getPath(), finalFileName)), AppUtils::getPassword);
PathUtils.combineUnix(fileBrowserView.getPath(), finalFileName)), AppUtils::getPassword, cancellationToken);
if (ret != 0) {
throw new Exception("Operation failed");
}
Expand All @@ -104,7 +104,7 @@ public void newOrRename(Action action) {
case NewFolder:
if (retryWithSudo.get()) {
var ret = SudoUtils.exec(fileBrowserView.getSessionInfo(), String.format("mkdir '%s'",
PathUtils.combineUnix(fileBrowserView.getPath(), finalFileName)), AppUtils::getPassword);
PathUtils.combineUnix(fileBrowserView.getPath(), finalFileName)), AppUtils::getPassword, cancellationToken);
if (ret != 0) {
throw new Exception("Operation failed");
}
Expand All @@ -119,14 +119,6 @@ public void newOrRename(Action action) {
}, retryWithSudo);
}

public void sameOriginCopy() {
var selected = fileBrowserView.getSelectedFiles();
if (selected.size() == 0) {
return;
}
sameOriginCopy(selected, fileBrowserView.getPath(), false);
}

public void sameOriginCopy(List<FileInfo> files, String folder, boolean overwrite) {
var fileSet = fileBrowserView.getAllFiles().stream().map(FileInfo::getName).collect(Collectors.toSet());
var args = new ArrayList<String>();
Expand Down Expand Up @@ -161,14 +153,14 @@ public void sameOriginCopy(List<FileInfo> files, String folder, boolean overwrit
}
if (retryWithSudo.get()) {
var ret = SudoUtils.exec(fileBrowserView.getSessionInfo(),
String.format("sh -c \"%s\"", command), AppUtils::getPassword);
String.format("sh -c \"%s\"", command), AppUtils::getPassword, cancellationToken);
if (ret != 0) {
throw new Exception("Operation failed");
}
} else {
if (App.getMultiplexingSessionService().executeCommand(
this.fileBrowserView.getSession().getSessionInfo(),
command) != 0) {
command, cancellationToken) != 0) {
throw new FSAccessException("Operation failed");
}
}
Expand Down Expand Up @@ -222,7 +214,7 @@ public void delete() {
.collect(Collectors.joining(" ")));
if (retryWithSudo.get()) {
var ret = SudoUtils.exec(this.fileBrowserView.getSession().getSessionInfo(),
str, AppUtils::getPassword);
str, AppUtils::getPassword, cancellationToken);
if (ret != 0) {
if (ret == -2) {
throw new Exception("Operation cancelled");
Expand All @@ -231,7 +223,7 @@ public void delete() {
}
return;
}
if (App.getMultiplexingSessionService().executeCommand(this.fileBrowserView.getSession().getSessionInfo(), str) == 0) {
if (App.getMultiplexingSessionService().executeCommand(this.fileBrowserView.getSession().getSessionInfo(), str, cancellationToken) == 0) {
System.out.println("Shell delete success!");
return;
}
Expand Down Expand Up @@ -273,18 +265,16 @@ public void delete() {
}

public void compress() {
var stopFlag = new AtomicBoolean(false);
var selected = fileBrowserView.getSelectedFiles();

var arcOps = new ArchiveOperations();
arcOps.createArchive(fileBrowserView.getSessionInfo(), selected.stream().map(FileInfo::getPath).toList(), fileBrowserView.getPath(), stopFlag);
arcOps.createArchive(fileBrowserView.getSessionInfo(), selected.stream().map(FileInfo::getPath).toList(), fileBrowserView.getPath());
}

public void extract() {
var stopFlag = new AtomicBoolean(false);
var selected = fileBrowserView.getSelectedFiles();
var arcOps = new ArchiveOperations();
arcOps.extractArchive(fileBrowserView.getSessionInfo(), selected.get(0).getPath(), fileBrowserView.getPath(), stopFlag);
arcOps.extractArchive(fileBrowserView.getSessionInfo(), selected.get(0).getPath(), fileBrowserView.getPath());
}

private void traverse(String path, ArrayList<String> files, ArrayList<String> folders, CancellationToken cancellationToken)
Expand All @@ -296,6 +286,9 @@ private void traverse(String path, ArrayList<String> files, ArrayList<String> fo
}
for (var folder :
fileList.getFolders()) {
if (cancellationToken.isCancellationRequested()) {
return;
}
if (folder.getFileType() == FileType.Directory) {
traverse(folder.getPath(), files, folders, cancellationToken);
} else {
Expand Down Expand Up @@ -432,12 +425,12 @@ public void copy(String targetFolder, List<FileInfo> sourceFiles) {
var str = String.format("cp -rf %s '%s'", String.join(" ", files), targetFolder);
System.out.println(str);
if (retryWithSudo.get()) {
var ret = SudoUtils.exec(fileBrowserView.getSessionInfo(), str, AppUtils::getPassword);
var ret = SudoUtils.exec(fileBrowserView.getSessionInfo(), str, AppUtils::getPassword, cancellationToken);
if (ret != 0) {
throw new Exception("Operation failed");
}
} else {
if (App.getMultiplexingSessionService().executeCommand(this.fileBrowserView.getSession().getSessionInfo(), str) != 0) {
if (App.getMultiplexingSessionService().executeCommand(this.fileBrowserView.getSession().getSessionInfo(), str, cancellationToken) != 0) {
throw new FSAccessException("Operation failed");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import muon.App;
import muon.dto.session.SessionInfo;
import muon.misc.CancellationToken;
import muon.util.AppUtils;
import muon.util.PathUtils;

Expand Down Expand Up @@ -89,8 +90,8 @@ private String getArchiveFileName(String archivePath) {
public void extractArchive(
SessionInfo sessionInfo,
String archivePath,
String targetFolder,
AtomicBoolean stopFlag) {
String targetFolder) {
var cancellationToken = new CancellationToken();
String command = getExtractCommand(archivePath);
if (command == null) {
System.out.println("Unsupported file: " + archivePath);
Expand All @@ -105,14 +106,14 @@ public void extractArchive(
System.out.println("Invoke command: " + command);
String finalCommand = command;
App.getAppWindow().blockInput(true, "Please wait...", "", e -> {
stopFlag.set(true);
cancellationToken.requestCancellation();
});
AppUtils.runAsync(() -> {
try {
var ret = App.getMultiplexingSessionService().executeCommand(
sessionInfo,
finalCommand,
stopFlag);
cancellationToken);
System.out.println("output: " + ret);
if (ret != 0) {
AppUtils.swingInvokeSync(() -> JOptionPane.showMessageDialog(null, "Operation failed"));
Expand All @@ -128,8 +129,8 @@ public void extractArchive(
public void createArchive(
SessionInfo sessionInfo,
List<String> files,
String targetFolder,
AtomicBoolean stopFlag) {
String targetFolder) {
var cancellationToken = new CancellationToken();
String text = files.size() > 1 ? PathUtils.getFileName(targetFolder)
: files.get(0);
JTextField txtFileName = new JTextField(text);
Expand All @@ -156,12 +157,12 @@ public void createArchive(
String cd = String.format("cd \"%s\";", txtTargetFolder.getText());
System.out.println(cd + compressCmd);
App.getAppWindow().blockInput(true, "Please wait...", "", e -> {
stopFlag.set(true);
cancellationToken.requestCancellation();
});
AppUtils.runAsync(() -> {
try {
var ret = App.getMultiplexingSessionService().executeCommand(
sessionInfo, cd + compressCmd, stopFlag);
sessionInfo, cd + compressCmd, cancellationToken);
System.out.println("output: " + ret);
if (ret != 0) {
AppUtils.swingInvokeSync(() -> JOptionPane.showMessageDialog(null, "Operation failed"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package muon.screens.appwin.filebrowser.transfer.foreground;

import muon.exceptions.FSAccessException;
import muon.misc.CancellationToken;
import muon.service.SftpUploadTask;
import muon.service.TransferTask;
import muon.util.AppUtils;
Expand All @@ -20,6 +21,7 @@ public class ForegroundTransferPanel extends JPanel {
private Consumer<Boolean> callback;
private TransferProgressPanel transferProgressPanel;
private TransferRetryPanel transferRetryPanel;
private CancellationToken cancellationToken;

public ForegroundTransferPanel() {
super(new CardLayout());
Expand All @@ -34,7 +36,12 @@ public void submitTask(TransferTask transferTask,

public void showProgress() {
if (transferProgressPanel == null) {
transferProgressPanel = new TransferProgressPanel(e -> this.transferTask.requestCancellation());
transferProgressPanel = new TransferProgressPanel(e -> {
this.transferTask.requestCancellation();
if (Objects.nonNull(this.cancellationToken)) {
this.cancellationToken.requestCancellation();
}
});
this.add(transferProgressPanel, "TransferProgressPanel");
}
transferProgressPanel.setProgress(0);
Expand Down Expand Up @@ -79,6 +86,7 @@ public void transfer() {
AppUtils.runAsync(() -> {
var retry = new AtomicBoolean(false);
do {
cancellationToken = new CancellationToken();
try {
transferFiles();
if (retry.get() && this.transferTask instanceof SftpUploadTask && !StringUtils.isEmpty(((SftpUploadTask) this.transferTask).getActualTargetPath())) {
Expand Down Expand Up @@ -117,7 +125,7 @@ private void copyUsingSudo(String source, String target) throws Exception {
transferProgressPanel.setStatus("Running shell command...");
});
var ret = SudoUtils.exec(((SftpUploadTask) this.transferTask).getSftpProvider().getSessionInfo(),
command, out, err, AppUtils::getPassword);
command, out, err, AppUtils::getPassword, cancellationToken);
if (ret != 0) {
if (ret == -2) {
throw new Exception("Operation cancelled");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import muon.dto.session.SessionInfo;
import muon.exceptions.FSAccessException;
import muon.exceptions.FSConnectException;
import muon.misc.CancellationToken;
import muon.screens.appwin.toolbox.PageContainer;
import muon.util.AppUtils;
import muon.util.ScriptLoader;
Expand Down Expand Up @@ -105,7 +106,7 @@ private void kill(ActionEvent actionEvent) {
try {
var out = new ByteArrayOutputStream();
var err = new ByteArrayOutputStream();
var ret = SudoUtils.exec(sessionInfo, "kill -9 " + pid, out, err, this.pageContainer::getPassword);
var ret = SudoUtils.exec(sessionInfo, "kill -9 " + pid, out, err, this.pageContainer::getPassword, new CancellationToken());
if (ret != 0) {
//Notify sudo failed
if (ret == -2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import muon.App;
import muon.dto.session.SessionInfo;
import muon.misc.CancellationToken;
import muon.screens.appwin.toolbox.PageContainer;
import muon.util.AppUtils;
import muon.util.SudoUtils;
Expand Down Expand Up @@ -411,7 +412,7 @@ private void performServiceAction(int option) {
public boolean runCommandWithSudo(String command) throws Exception {
var out = new ByteArrayOutputStream();
var err = new ByteArrayOutputStream();
return SudoUtils.exec(this.sessionInfo, command, out, err, this.pageContainer::getPassword) == 0;
return SudoUtils.exec(this.sessionInfo, command, out, err, this.pageContainer::getPassword, new CancellationToken()) == 0;
}

public boolean runCommand(String command) throws Exception {
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/muon/screens/sessionmgr/SshInfoPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class SshInfoPanel extends JPanel {
private SessionInfo sessionInfo;
private JLabel lblPassword, lblKeyFile, lblIdentity, lblUserName;
private JButton btnBrowseKey, btnEditIdentities;
private JCheckBox chkUseSudo;

public SshInfoPanel() {
super(new GridBagLayout());
Expand All @@ -46,6 +47,7 @@ public SshInfoPanel() {
txtLocalFolder = new JTextField();
cmbStartPage = new JComboBox<>(new String[]{"SFTP+Terminal", "SFTP", "Terminal", "Port forwarding"});
swCombinedMode = new SwitchButton();
chkUseSudo = new JCheckBox("Login with sudo privilege");

cmbStartPage.setFont(cmbFont);
txtPass.setEchoChar('*');
Expand Down Expand Up @@ -73,6 +75,9 @@ public SshInfoPanel() {
attachTextListener(txtKeyFile, text -> sessionInfo.setPrivateKeyFile(text));
attachTextListener(txtRemoteFolder, text -> sessionInfo.setRemoteFolder(text));
attachTextListener(txtLocalFolder, text -> sessionInfo.setLocalFolder(text));
chkUseSudo.addChangeListener(e -> {
sessionInfo.setLoginAsSudo(chkUseSudo.isSelected());
});

attachPasswordListener(txtPass, password -> {
sessionInfo.setPassword(new String(password));
Expand Down Expand Up @@ -104,6 +109,7 @@ public void setValue(SessionInfo info) {
txtLocalFolder.setText(info.getLocalFolder());
cmbAuthMethod.setSelectedIndex(info.getAuthMode());
txtPass.setText(info.getPassword());
chkUseSudo.setSelected(false);
}

private void attachTextListener(JTextField txt, Consumer<String> consumer) {
Expand Down Expand Up @@ -371,6 +377,17 @@ private void createUI() {

c++;

gc = new GridBagConstraints();
gc.gridx = 1;
gc.gridy = c;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.gridwidth = 2;
gc.weightx = 1;
gc.insets = insets;
this.add(chkUseSudo, gc);

c++;

gc = new GridBagConstraints();
gc.gridx = 0;
gc.gridy = c;
Expand Down
Loading

0 comments on commit 2134d5d

Please sign in to comment.