Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
xmlns:tools="http://schemas.android.com/tools">

<permission android:name="${applicationId}.permission.CONTROL_FTP_SERVER"
android:protectionLevel="signature" />

<permission android:name="${applicationId}.permission.CONTROL_FTP_SERVER_SIMPLE"
android:label="@string/permission_ftp_control_simple_label"
android:description="@string/permission_ftp_control_simple_description"
android:protectionLevel="dangerous" />

<uses-permission android:name="android.permission.WAKE_LOCK" />
Expand Down Expand Up @@ -313,6 +318,16 @@
</intent-filter>
</receiver>

<receiver
android:name=".asynchronous.services.ftp.FtpExternalControlReceiver"
android:exported="true"
android:permission="${applicationId}.permission.CONTROL_FTP_SERVER_SIMPLE">
<intent-filter>
<action android:name="com.amaze.filemanager.action.EXTERNAL_START_FTP" />
<action android:name="com.amaze.filemanager.action.EXTERNAL_STOP_FTP" />
</intent-filter>
</receiver>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2014-2026 Arpit Khurana <arpitkh96@gmail.com>, Vishal Nehra <vishalmeham2@gmail.com>,
* Emmanuel Messulam<emmanuelbendavid@gmail.com>, Raymond Lai <airwave209gt at gmail.com> and Contributors.
*
* This file is part of Amaze File Manager.
*
* Amaze File Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.amaze.filemanager.asynchronous.services.ftp

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.content.ContextCompat
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/**
* Receiver for third-party apps (e.g. Tasker) holding the dangerous
* CONTROL_FTP_SERVER_SIMPLE permission. Only starts/stops the server with the user's saved
* settings; extras of the incoming intent are deliberately never forwarded.
*/
class FtpExternalControlReceiver : BroadcastReceiver() {
companion object {
private val logger: Logger = LoggerFactory.getLogger(FtpExternalControlReceiver::class.java)
}

override fun onReceive(
context: Context,
intent: Intent,
) {
val service = Intent(context, FtpService::class.java)
runCatching {
when (intent.action) {
FtpService.ACTION_EXTERNAL_START_FTP -> {
if (!FtpService.isRunning()) {
ContextCompat.startForegroundService(context, service)
}
}

FtpService.ACTION_EXTERNAL_STOP_FTP -> {
context.stopService(service)
}

else -> {
Unit
}
}
}.onFailure {
logger.error("Failed to start/stop on intent ${it.message}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,45 @@ package com.amaze.filemanager.asynchronous.services.ftp
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.content.ContextCompat
import com.amaze.filemanager.BuildConfig.DEBUG
import com.amaze.filemanager.asynchronous.services.ftp.FtpService.Companion.isRunning
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/** Created by yashwanthreddyg on 09-06-2016. */
class FtpReceiver : BroadcastReceiver() {
private val TAG = FtpReceiver::class.java.simpleName
companion object {
private val logger: Logger = LoggerFactory.getLogger(FtpReceiver::class.java)
}

override fun onReceive(
context: Context,
intent: Intent,
) {
if (DEBUG) {
Log.v(TAG, "Received: ${intent.action}")
logger.debug("Received: ${intent.action}")
}
val service = Intent(context, FtpService::class.java)
service.putExtras(intent)
runCatching {
if (intent.action == FtpService.ACTION_START_FTPSERVER && !isRunning()) {
ContextCompat.startForegroundService(context, service)
} else if (intent.action == FtpService.ACTION_STOP_FTPSERVER) {
context.stopService(service)
} else {
Unit
when (intent.action) {
FtpService.ACTION_START_FTPSERVER -> {
if (!isRunning()) {
ContextCompat.startForegroundService(context, service)
}
}

FtpService.ACTION_STOP_FTPSERVER -> {
context.stopService(service)
}

else -> {
Unit
}
}
}.onFailure {
Log.e(TAG, "Failed to start/stop on intent ${it.message}")
logger.error("Failed to start/stop on intent ${it.message}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ import kotlin.concurrent.thread
*
* Edited by zent-co on 30-07-2019 Edited by bowiechen on 2019-10-19.
*/
class FtpService : Service(), Runnable {
class FtpService :
Service(),
Runnable {
private val binder: IBinder = ObtainableServiceBinder(this)

// Service will broadcast via event bus when server start/stop
Expand Down Expand Up @@ -137,9 +139,7 @@ class FtpService : Service(), Runnable {
wakeLock.setReferenceCounted(false)
}

override fun onBind(intent: Intent): IBinder {
return binder
}
override fun onBind(intent: Intent): IBinder = binder

@Suppress("LongMethod")
override fun run() {
Expand Down Expand Up @@ -243,7 +243,8 @@ class FtpService : Service(), Runnable {
server =
createServer().apply {
start()
EventBus.getDefault()
EventBus
.getDefault()
.post(
if (isStartedByTile) {
FtpReceiverActions.STARTED_FROM_TILE
Expand Down Expand Up @@ -315,37 +316,40 @@ class FtpService : Service(), Runnable {
"com.amaze.filemanager.services.ftpservice.FTPReceiver.ACTION_START_FTPSERVER"
const val ACTION_STOP_FTPSERVER =
"com.amaze.filemanager.services.ftpservice.FTPReceiver.ACTION_STOP_FTPSERVER"
const val ACTION_EXTERNAL_START_FTP = "com.amaze.filemanager.action.EXTERNAL_START_FTP"
const val ACTION_EXTERNAL_STOP_FTP = "com.amaze.filemanager.action.EXTERNAL_STOP_FTP"
const val TAG_STARTED_BY_TILE = "started_by_tile"
// attribute of action_started, used by notification

private var _enabledCipherSuites: Array<String> =
LinkedList<String>().apply {
if (SDK_INT >= Q) {
add("TLS_AES_128_GCM_SHA256")
add("TLS_AES_256_GCM_SHA384")
add("TLS_CHACHA20_POLY1305_SHA256")
}
if (SDK_INT >= N) {
add("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
add("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")
}
if (SDK_INT >= LOLLIPOP) {
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")
add("TLS_RSA_WITH_AES_128_GCM_SHA256")
add("TLS_RSA_WITH_AES_256_GCM_SHA384")
}
if (SDK_INT < LOLLIPOP) {
add("TLS_RSA_WITH_AES_128_CBC_SHA")
add("TLS_RSA_WITH_AES_256_CBC_SHA")
}
}.toTypedArray()
LinkedList<String>()
.apply {
if (SDK_INT >= Q) {
add("TLS_AES_128_GCM_SHA256")
add("TLS_AES_256_GCM_SHA384")
add("TLS_CHACHA20_POLY1305_SHA256")
}
if (SDK_INT >= N) {
add("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
add("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")
}
if (SDK_INT >= LOLLIPOP) {
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")
add("TLS_RSA_WITH_AES_128_GCM_SHA256")
add("TLS_RSA_WITH_AES_256_GCM_SHA384")
}
if (SDK_INT < LOLLIPOP) {
add("TLS_RSA_WITH_AES_128_CBC_SHA")
add("TLS_RSA_WITH_AES_256_CBC_SHA")
}
}.toTypedArray()

/**
* Return a list of available ciphers for ftpserver.
Expand All @@ -369,18 +373,19 @@ class FtpService : Service(), Runnable {
* based URI if it's running on Android 7.0 or above.
*/
@JvmStatic
fun defaultPath(context: Context): String {
return if (PreferenceManager.getDefaultSharedPreferences(context)
fun defaultPath(context: Context): String =
if (PreferenceManager
.getDefaultSharedPreferences(context)
.getBoolean(KEY_PREFERENCE_SAF_FILESYSTEM, false) && SDK_INT > M
) {
DocumentsContract.buildTreeDocumentUri(
"com.android.externalstorage.documents",
"primary:",
).toString()
DocumentsContract
.buildTreeDocumentUri(
"com.android.externalstorage.documents",
"primary:",
).toString()
} else {
Environment.getExternalStorageDirectory().absolutePath
}
}

/**
* Indicator whether FTP service is running
Expand All @@ -391,8 +396,6 @@ class FtpService : Service(), Runnable {
return !server.isStopped
}

private fun getPort(preferences: SharedPreferences): Int {
return preferences.getInt(PORT_PREFERENCE_KEY, DEFAULT_PORT)
}
private fun getPort(preferences: SharedPreferences): Int = preferences.getInt(PORT_PREFERENCE_KEY, DEFAULT_PORT)
}
}
Loading
Loading