Support for ftps

This commit is contained in:
2024-09-14 23:51:17 -07:00
parent 240e7f3677
commit d76fda9bfd
8 changed files with 262 additions and 109 deletions
+81 -6
View File
@@ -7,6 +7,7 @@ import java.net.ProtocolException;
import java.net.URI;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
@@ -34,6 +35,7 @@ public class RemoteStore {
private final FTPClient ftp;
private int connectionLevel = 0;
private boolean ignoreManifest = false;
private boolean passiveMode;
public RemoteStoreFileTypeHandler fileTypeHandler = new RemoteStoreFileTypeHandler();
@@ -42,10 +44,13 @@ public class RemoteStore {
if (!url.isAbsolute() || url.getScheme().equals("ftp")) {
ftp = new FTPClient();
} else if (url.getScheme().equals("ftps")) {
ftp = new FTPSClient(false);
ftp = new FTPSClient("TLS", false);
((FTPSClient) ftp).setEndpointCheckingEnabled(true);
} else {
throw new ProtocolException("unknown protocol: '" + url.getScheme() + "'");
}
ftp.addProtocolCommandListener(new PrintCommandListener(System.out, true));
ftp.setListHiddenFiles(true);
this.secrets = secrets;
}
@@ -61,6 +66,24 @@ public class RemoteStore {
this.ignoreManifest = ignoreManifest;
}
public boolean isPassiveMode() {
return passiveMode;
}
public void setPassiveMode(boolean passiveMode) throws IOException {
this.passiveMode = passiveMode;
if (connectionLevel != 0) {
String modeString = passiveMode ? "passive" : "active";
LOGGER.info("Switching to " + modeString + " mode");
if (passiveMode) {
ftp.enterLocalPassiveMode();
} else {
ftp.enterLocalActiveMode();
}
checkFtpResponse("Failed to switch to " + modeString + " mode");
}
}
public void fetchManifest() throws IOException {
doFtpActions(() -> {
FTPFile info = fileInformation(MANIFEST_PATH);
@@ -199,10 +222,31 @@ public class RemoteStore {
return fileInformation(path) != null;
}
private boolean isRootDir(String path) {
return path.matches("^(/+\\.{0,2})+$");
}
public FTPFile fileInformation(String path) throws IOException {
if (isRootDir(path)) {
return null;
}
AtomicReference<FTPFile> file = new AtomicReference<FTPFile>();
doFtpActions(() -> {
file.set(ftp.mlistFile(resolvePath(path)));
String pp = getParentPath(path);
if (pp == null) {
pp = getBasePath();
}
String name = getFileName(path);
FTPFile[] files = ftp.listFiles(pp);
System.out.println("STAT " + name + " in " + pp);
for (FTPFile f : files) {
System.out.println(
(f.isDirectory() ? "D " : "F ") +
f.getName());
if (f.getName().equals(name)) {
file.set(f);
}
}
});
return file.get();
}
@@ -216,6 +260,14 @@ public class RemoteStore {
throw new IOException("Invalid ftp secrets! Username: '" + secrets.getUsername() + "'");
}
LOGGER.info("Logged info ftp as user '{}'", secrets.getUsername());
if (ftp instanceof FTPSClient) {
FTPSClient ftps = (FTPSClient) ftp;
ftps.execPBSZ(0);
checkFtpResponse("Failed to send PBSZ command");
ftps.execPROT("P");
checkFtpResponse("Failed to send PROT command");
}
setPassiveMode(passiveMode);
}
}
@@ -307,7 +359,10 @@ public class RemoteStore {
pb.append("/");
ftp.makeDirectory(pb.toString());
}
checkFtpResponse("Could not create directory: " + pp);
info = fileInformation(pp);
// if (info == null || !info.isDirectory()) {
// throw new IOException("Failed to create directory: " + pp);
// }
LOGGER.info("Created directory: {}", pp);
} else if (!info.isDirectory()) {
throw new IOException("Not a directory: " + pp);
@@ -319,8 +374,15 @@ public class RemoteStore {
if (ftp.isConnected()) {
int r = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(r)) {
LOGGER.info(error);
throw new IOException(error);
String replyString = ftp.getReplyString();
if (replyString.endsWith("\n")) {
replyString = replyString.substring(0, replyString.length() - 1);
}
if (replyString.endsWith(".")) {
replyString = replyString.substring(0, replyString.length() - 1);
}
LOGGER.info("{}: {}", error, replyString);
throw new IOException(error + ": " + replyString);
}
}
}
@@ -365,6 +427,19 @@ public class RemoteStore {
if (i == -1) {
return null;
}
return cp.substring(0, i);
String pp = cp.substring(0, i);
while (!pp.isEmpty() && pp.charAt(pp.length() - 1) == '/') {
pp = pp.substring(0, pp.length() - 1);
}
return pp;
}
private static String getFileName(String path) {
String cp = cleanPath(path);
int i = cp.lastIndexOf("/");
if (i == -1) {
return cp;
}
return cp.substring(i + 1);
}
}