From 5dd128f4f3993957b199ecb24065878ca33f4502 Mon Sep 17 00:00:00 2001 From: Priyanshu Jain Date: Mon, 26 Oct 2026 13:24:53 +0530 Subject: [PATCH 1/2] fix(ftp): honor FTPS security type and connect arg order Ftp.java read the connect args at the wrong indexes (JS sends host, port, username, password, connectionMode, securityType, encoding), so active mode could never be enabled, and securityType was read but never used, so every connection was plain FTP. Use explicit FTPSClient (AUTH TLS) when securityType is "ftps" and send PBSZ 0 / PROT P after login so the data channel is encrypted too. Fixes #2979 --- .../ftp/src/android/com/foxdebug/ftp/Ftp.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java b/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java index b2de25446a..680c5d522b 100644 --- a/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java +++ b/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java @@ -78,6 +78,11 @@ public void connect(JSONArray args, CallbackContext callback) { connect(args, callback, false); } + private FTPClient createClient(String securityType) { + // explicit FTPS: AUTH TLS on the normal port + return "ftps".equals(securityType) ? new FTPSClient(false) : new FTPClient(); + } + public void connect( JSONArray args, CallbackContext callback, @@ -93,11 +98,10 @@ public void run() { String host = args.optString(0); String username = args.optString(2); String password = args.optString(3); - String defaultPath = args.optString(4); + // order must match www/ftp.js connect() + 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 +122,11 @@ public void run() { 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 +155,12 @@ public void run() { return; } + if (ftp instanceof FTPSClient) { + // RFC 4217: protect the data channel too + ((FTPSClient) ftp).execPBSZ(0); + ((FTPSClient) ftp).execPROT("P"); + } + ftp.setListHiddenFiles(true); ftpProfiles.put(ftpId, ftp); Log.d("FTP", "FTPClient (" + ftpId + ") connected"); From d9e38874723b9333ceaa0f10e2f30f5381ba98ef Mon Sep 17 00:00:00 2001 From: Priyanshu Jain Date: Mon, 26 Oct 2026 14:09:49 +0530 Subject: [PATCH 2/2] fix(ftp): don't reuse cached client across security types The profile id ignores security type and editing a profile does not disconnect, so switching FTP to FTPS could keep returning the old plain client. Only reuse the cached client when its type matches. --- src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java b/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java index 680c5d522b..18cf783036 100644 --- a/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java +++ b/src/plugins/ftp/src/android/com/foxdebug/ftp/Ftp.java @@ -109,7 +109,14 @@ public void run() { if (ftpProfiles.containsKey(ftpId)) { ftp = ftpProfiles.get(ftpId); reply = ftp.getReplyCode(); - if (ftp.isConnected() && FTPReply.isPositiveCompletion(reply)) { + // ftpId ignores security, so don't reuse a client of the other type + boolean sameSecurity = + (ftp instanceof FTPSClient) == "ftps".equals(securityType); + if ( + sameSecurity && + ftp.isConnected() && + FTPReply.isPositiveCompletion(reply) + ) { ftp.setControlEncoding("UTF-8"); ftp.setAutodetectUTF8(true); System.setProperty("ftp.client.encoding", "UTF-8");