Repository navigation
FTPS option in "Add FTP" is ignored by the native plugin – connections always use plain FTP #2979
Description
Check for existing issues
- Completed
Describe the bug / provide steps to reproduce it
Summary
The "Add FTP" dialog offers Security type: FTP / FTPS, and the selected value is correctly passed down to the native Android plugin. However, the native code never uses it and always creates a plain FTPClient. As a result, servers that require explicit FTPS (AUTH TLS) cannot be used at all: Acode sends USER/PASS over an unencrypted control channel and the server rejects the login.
This also seems to be the cause of the old issue #85 (SSLHandshakeFailed with FTPS / 530 Please login with USER and PASS with FTP).
Steps to reproduce
- Use an FTP server that requires explicit TLS on port 21 (AUTH TLS, e.g. vsftpd with
force_local_logins_ssl=YESor ProFTPD withTLSRequired on). - In Acode: File browser → + → FTP.
- Fill in host, port
21, username, password, select FTPS and confirm.
Expected: Acode negotiates TLS (AUTH TLS), logs in and lists the directory.
Actual: The connection is made without TLS and the server refuses the login (e.g. 530, or "TLS required on the control channel").
The same server works fine with other clients (WinSCP, FileZilla) using "FTP – TLS/SSL explicit encryption".
Root cause
src/lib/remoteStorage.js– the dialog setssecurity = "ftps".src/fileSystem/ftp.js→src/plugins/ftp/www/ftp.js–securityTypeis passed tocordova.execas argument index 5:
[host, port, username, password, connectionMode, securityType, encoding]src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java–connect():securityTypeis read (args.optString(5)) but never used,- the client is always created as
new FTPClient(), so no TLS is ever negotiated.
Related bug (same method)
The argument indexes in Ftp.java do not match the order sent from ftp.js. Java reads connectionMode from index 6 (which is encoding) and encoding from index 8. Therefore active mode can never be enabled: connectionMode is never "active", so passive mode is always used.
Proposed fix
Only Ftp.java needs to change. commons-net:3.12.0 is already a dependency and FTPSClient is in the already imported org.apache.commons.net.ftp.* package, so no new dependency or JS change is needed.
@@ -78,6 +78,11 @@ public class Ftp extends CordovaPlugin {
connect(args, callback, false);
}
+ private FTPClient createClient(String securityType) {
+ // Explicit FTPS (AUTH TLS on the standard port), isImplicit = false
+ return "ftps".equals(securityType) ? new FTPSClient(false) : new FTPClient();
+ }
+
public void connect(
JSONArray args,
CallbackContext callback,
@@ -93,11 +98,9 @@ public class Ftp extends CordovaPlugin {
String host = args.optString(0);
String username = args.optString(2);
String password = args.optString(3);
- String defaultPath = args.optString(4);
+ String connectionMode = args.optString(4);
String securityType = args.optString(5);
- String connectionMode = args.optString(6);
- String encryption = args.optString(7);
- String encoding = args.optString(8);
+ String encoding = args.optString(6);
String ftpId = getFtpId(host, port, username);
FTPClient ftp = null;
@@ -118,9 +121,11 @@ public class Ftp extends CordovaPlugin {
Log.d("FTP", "FTPClient (" + ftpId + ") is not connected");
ftp.disconnect();
Log.d("FTP", "FTPClient (" + ftpId + ") disconnecting...");
+ ftp = createClient(securityType);
+ ftpProfiles.put(ftpId, ftp);
} else {
Log.d("FTP", "Creating new FTPClient (" + ftpId + ")");
- ftp = new FTPClient();
+ ftp = createClient(securityType);
ftpProfiles.put(ftpId, ftp);
}
@@ -149,6 +154,12 @@ public class Ftp extends CordovaPlugin {
return;
}
+ if (ftp instanceof FTPSClient) {
+ // RFC 4217: protect the data channel (PBSZ 0 + PROT P) after AUTH TLS
+ ((FTPSClient) ftp).execPBSZ(0);
+ ((FTPSClient) ftp).execPROT("P");
+ }
+
ftp.setListHiddenFiles(true);
ftpProfiles.put(ftpId, ftp);
Log.d("FTP", "FTPClient (" + ftpId + ") connected");Notes
- TLS session reuse: some servers (vsftpd with the default
require_ssl_reuse=YES, ProFTPD withoutTLSOptions NoSessionReuseRequired) require the data connection to reuse the control connection's TLS session. Commons NetFTPSClientdoes not do this by default, so directory listings/transfers may fail on such servers (e.g.522 SSL connection failed: session reuse required). This would need an additional workaround in_prepareDataSocket_(). - Certificate validation:
FTPSClientuses a permissive trust manager by default. It may be worth adding proper certificate/hostname validation or a "trust this certificate" prompt. - Implicit FTPS (port 990) is not covered. It could be added later as a separate option (
new FTPSClient(true)). - The diff above has not been compiled/tested against a full Cordova build yet.
Environment
Device Information:
WebView Info:
Package Name: com.google.android.webview
Version: 155.0.8059.43
App Info:
Name: Acode
Package Name: com.foxdebug.acodefree
Version: 1.13.5
Version Code: 1011
Device Info:
Android Version: 17
Manufacturer: samsung
Model: SM-X840
Platform: Android
Cordova Version: 15.1.0
Screen Info:
Width: 1400
Height: 876
Color Depth: 24
Additional Info:
Language: cs-CZ
User Agent: Mozilla/5.0 (Linux; Android 17; SM-X840 Build/CP2A.260605.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/155.0.8059.43 Safari/537.36
If applicable, add mockups / screenshots regarding your vision
No response
If applicable, attach your Acode.log file to this issue.
Acode.log
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity