From dfb26a0d2c95d56f69f5e1e0c255d9d5d6788120 Mon Sep 17 00:00:00 2001
From: pacien
Date: Sat, 29 Jul 2023 23:03:12 +0200
Subject: storage: remove embedded FTP server
Moving back the configuration files and logs to the user-accessible
storage. Everything should be accessible through a file manager using
the "USB storage" mode. The embedded FTP server is no longer
necessary.
---
app/build.gradle | 12 --
app/proguard-rules.pro | 4 +-
app/src/main/AndroidManifest.xml | 7 -
.../configure/ConfigurationAccessServerFragment.kt | 77 --------
.../tincapp/context/AppNotificationManager.kt | 13 --
.../tincapp/service/ConfigurationAccessService.kt | 204 ---------------------
app/src/main/res/layout/configure_activity.xml | 14 +-
...nfigure_tools_configuration_access_fragment.xml | 86 ---------
app/src/main/res/values-ru-rRU/strings.xml | 10 -
app/src/main/res/values/strings.xml | 10 -
readme.md | 1 -
11 files changed, 3 insertions(+), 435 deletions(-)
delete mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/ConfigurationAccessServerFragment.kt
delete mode 100644 app/src/main/java/org/pacien/tincapp/service/ConfigurationAccessService.kt
delete mode 100644 app/src/main/res/layout/configure_tools_configuration_access_fragment.xml
diff --git a/app/build.gradle b/app/build.gradle
index 5d2da3f..5d49965 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -71,17 +71,6 @@ android {
dataBinding = true
}
- packagingOptions {
- resources {
- excludes += [
- 'META-INF/DEPENDENCIES',
- 'META-INF/spring.schemas',
- 'META-INF/spring.handlers',
- 'META-INF/license.txt',
- ]
- }
- }
-
namespace 'org.pacien.tincapp'
}
@@ -101,7 +90,6 @@ dependencies {
implementation('org.apache.commons:commons-configuration2:2.3') { exclude group: 'commons-logging', module: 'commons-logging' }
implementation('commons-beanutils:commons-beanutils:1.9.3') { exclude group: 'commons-logging', module: 'commons-logging' }
implementation('commons-io:commons-io:2.6') { exclude group: 'commons-logging', module: 'commons-logging' }
- implementation('org.apache.ftpserver:ftpserver:1.1.1') { exclude group: 'org.slf4j', module: 'slf4j-log4j12' }
}
repositories {
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index ffbb3e3..2bb4a71 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,5 +1,5 @@
# Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
-# Copyright (C) 2017-2020 Pacien TRAN-GIRARD
+# Copyright (C) 2017-2023 Pacien TRAN-GIRARD
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,8 +15,6 @@
# along with this program. If not, see .
-keep class org.apache.commons.** { *; }
--keep class org.apache.mina.** { *; }
--keep class org.apache.ftpserver.** { *; }
-keep class org.bouncycastle.**
-keep class ch.qos.** { *; }
-keep class org.slf4j.** { *; }
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8d71109..827f421 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,9 +26,6 @@
-
-
-
@@ -91,10 +88,6 @@
-
-
-
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/ConfigurationAccessServerFragment.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/ConfigurationAccessServerFragment.kt
deleted file mode 100644
index c90299a..0000000
--- a/app/src/main/java/org/pacien/tincapp/activities/configure/ConfigurationAccessServerFragment.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
- * Copyright (C) 2017-2020 Pacien TRAN-GIRARD
- *
- * This program 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 .
- */
-
-package org.pacien.tincapp.activities.configure
-
-import android.content.Intent
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.databinding.Observable
-import androidx.databinding.ObservableBoolean
-import org.pacien.tincapp.activities.BaseFragment
-import org.pacien.tincapp.databinding.ConfigureToolsConfigurationAccessFragmentBinding
-import org.pacien.tincapp.service.ConfigurationAccessService
-
-/**
- * @author pacien
- */
-class ConfigurationAccessServerFragment : BaseFragment() {
- private val ftpServerStartListener = object : Observable.OnPropertyChangedCallback() {
- override fun onPropertyChanged(sender: Observable, propertyId: Int) {
- binding.ftpEnabled = (sender as ObservableBoolean).get()
- }
- }
-
- private lateinit var binding: ConfigureToolsConfigurationAccessFragmentBinding
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- binding = ConfigureToolsConfigurationAccessFragmentBinding.inflate(inflater, container, false)
- binding.toggleFtpState = { toggleServer() }
- setConnectionInfo()
- return binding.root
- }
-
- override fun onResume() {
- super.onResume()
- setConnectionInfo()
- ConfigurationAccessService.runningState.addOnPropertyChangedCallback(ftpServerStartListener)
- binding.ftpEnabled = ConfigurationAccessService.runningState.get()
- }
-
- override fun onPause() {
- ConfigurationAccessService.runningState.removeOnPropertyChangedCallback(ftpServerStartListener)
- super.onPause()
- }
-
- private fun setConnectionInfo() {
- binding.ftpUsername = ConfigurationAccessService.getFtpUsername()
- binding.ftpPassword = ConfigurationAccessService.getFtpPassword()
- binding.ftpPort = ConfigurationAccessService.getFtpPort()
- }
-
- private fun toggleServer() {
- val targetServiceIntent = Intent(requireContext(), ConfigurationAccessService::class.java)
-
- if (binding.ftpEnabled)
- requireContext().stopService(targetServiceIntent)
- else
- requireContext().startService(targetServiceIntent)
- }
-}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
index 5b01a54..d6e21f5 100644
--- a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
+++ b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
@@ -36,10 +36,7 @@ import org.pacien.tincapp.utils.PendingIntentUtils
class AppNotificationManager(private val context: Context) {
companion object {
private const val ERROR_CHANNEL_ID = "org.pacien.tincapp.notification.channels.error"
- private const val CONFIG_ACCESS_CHANNEL_ID = "org.pacien.tincapp.notification.channels.configuration"
-
const val ERROR_NOTIFICATION_ID = 0
- const val CONFIG_ACCESS_NOTIFICATION_ID = 1
}
init {
@@ -65,9 +62,6 @@ class AppNotificationManager(private val context: Context) {
NotificationManagerCompat.from(context).cancelAll()
}
- fun newConfigurationAccessNotificationBuilder() =
- NotificationCompat.Builder(context, CONFIG_ACCESS_CHANNEL_ID)
-
@RequiresApi(Build.VERSION_CODES.O)
private fun registerChannels() {
context.getSystemService(NotificationManager::class.java)
@@ -78,13 +72,6 @@ class AppNotificationManager(private val context: Context) {
NotificationManager.IMPORTANCE_HIGH
))
}
- .apply {
- createNotificationChannel(NotificationChannel(
- CONFIG_ACCESS_CHANNEL_ID,
- context.getString(R.string.notification_config_access_channel_name),
- NotificationManager.IMPORTANCE_MIN
- ))
- }
}
private fun NotificationCompat.Builder.setHighPriority() = apply {
diff --git a/app/src/main/java/org/pacien/tincapp/service/ConfigurationAccessService.kt b/app/src/main/java/org/pacien/tincapp/service/ConfigurationAccessService.kt
deleted file mode 100644
index 916f19d..0000000
--- a/app/src/main/java/org/pacien/tincapp/service/ConfigurationAccessService.kt
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
- * Copyright (C) 2017-2023 Pacien TRAN-GIRARD
- *
- * This program 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 .
- */
-
-package org.pacien.tincapp.service
-
-import android.app.Service
-import android.content.Context
-import android.content.Intent
-import android.os.IBinder
-import androidx.databinding.ObservableBoolean
-import ch.qos.logback.classic.Level
-import ch.qos.logback.classic.Logger
-import org.apache.ftpserver.ConnectionConfigFactory
-import org.apache.ftpserver.DataConnectionConfigurationFactory
-import org.apache.ftpserver.FtpServer
-import org.apache.ftpserver.FtpServerFactory
-import org.apache.ftpserver.ftplet.*
-import org.apache.ftpserver.listener.ListenerFactory
-import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication
-import org.apache.ftpserver.usermanager.impl.WritePermission
-import org.pacien.tincapp.R
-import org.pacien.tincapp.activities.configure.ConfigureActivity
-import org.pacien.tincapp.context.App
-import org.pacien.tincapp.context.AppNotificationManager
-import org.pacien.tincapp.extensions.Java.defaultMessage
-import org.pacien.tincapp.utils.PendingIntentUtils
-import org.slf4j.LoggerFactory
-import java.io.IOException
-
-/**
- * FTP server service allowing a remote and local user to access and modify configuration files in
- * the application's context.
- *
- * @author pacien
- */
-class ConfigurationAccessService : Service() {
- companion object {
- // Apache Mina FtpServer's INFO log level is actually VERBOSE.
- // The object holds static references to those loggers so that they stay around.
- @Suppress("unused")
- private val MINA_FTP_LOGGER_OVERRIDER = MinaLoggerOverrider(Level.WARN)
-
- private val context by lazy { App.getContext() }
- private val store by lazy { context.getSharedPreferences("${this::class.java.`package`!!.name}.ftp", Context.MODE_PRIVATE)!! }
- val runningState = ObservableBoolean(false)
-
- fun getFtpHomeDir(): String = context.applicationInfo.dataDir!!
- fun getFtpUsername() = storeGetOrInsertString("username") { "tincapp" }
- fun getFtpPassword() = storeGetOrInsertString("password") { generateRandomString(8) }
- fun getFtpPort() = storeGetOrInsertInt("port") { 65521 } // tinc port `concat` FTP port
- fun getFtpPassiveDataPorts() = storeGetOrInsertString("passive-range") { "65522-65532" }
-
- private fun storeGetOrInsertString(key: String, defaultGenerator: () -> String): String = synchronized(store) {
- if (!store.contains(key)) store.edit().putString(key, defaultGenerator()).apply()
- return store.getString(key, null)!!
- }
-
- private fun storeGetOrInsertInt(key: String, defaultGenerator: () -> Int): Int = synchronized(store) {
- if (!store.contains(key)) store.edit().putInt(key, defaultGenerator()).apply()
- return store.getInt(key, 0)
- }
-
- private fun generateRandomString(length: Int): String {
- val alphabet = ('a'..'z') + ('A'..'Z') + ('0'..'9')
- return List(length) { alphabet.random() }.joinToString("")
- }
- }
-
- private val log by lazy { LoggerFactory.getLogger(this.javaClass)!! }
- private val notificationManager by lazy { App.notificationManager }
- private var sftpServer: FtpServer? = null
-
- override fun onBind(intent: Intent): IBinder? = null // non-bindable service
-
- override fun onDestroy() {
- sftpServer?.stop()
- sftpServer = null
- runningState.set(false)
- log.info("Stopped FTP server")
- super.onDestroy()
- }
-
- override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- val ftpUser = StaticFtpUser(getFtpUsername(), getFtpPassword(), getFtpHomeDir(), listOf(WritePermission()))
- sftpServer = setupSingleUserServer(ftpUser, getFtpPort(), getFtpPassiveDataPorts()).also {
- try {
- it.start()
- runningState.set(true)
- log.info("Started FTP server on port {}", getFtpPort())
- pinInForeground()
- } catch (e: IOException) {
- log.error("Could not start FTP server", e)
- App.alert(R.string.notification_error_title_unable_to_start_ftp_server, e.defaultMessage())
- }
- }
-
- return START_NOT_STICKY
- }
-
- /**
- * Pins the service in the foreground so that it doesn't get stopped by the system when the
- * application's activities are put in the background, which is the case when the user sets the
- * focus on an FTP client app for example.
- */
- private fun pinInForeground() {
- startForeground(
- AppNotificationManager.CONFIG_ACCESS_NOTIFICATION_ID,
- notificationManager.newConfigurationAccessNotificationBuilder()
- .setSmallIcon(R.drawable.ic_baseline_folder_open_primary_24dp)
- .setContentTitle(resources.getString(R.string.notification_config_access_server_running_title))
- .setContentText(resources.getString(R.string.notification_config_access_server_running_message))
- .setContentIntent(Intent(this, ConfigureActivity::class.java).let {
- PendingIntentUtils.getActivity(this, 0, it, 0)
- })
- .build()
- )
- }
-
- private fun setupSingleUserServer(ftpUser: User, ftpPort: Int, ftpPassivePorts: String): FtpServer =
- FtpServerFactory()
- .apply {
- addListener("default", ListenerFactory()
- .apply {
- connectionConfig = ConnectionConfigFactory()
- .apply { maxThreads = 1 } // library has issues with multiple threads
- .createConnectionConfig()
- }
- .apply { port = ftpPort }
- .apply {
- dataConnectionConfiguration = DataConnectionConfigurationFactory()
- .apply { passivePorts = ftpPassivePorts }
- .createDataConnectionConfiguration()
- }
- .createListener()
- )
- }
- .apply { userManager = StaticFtpUserManager(listOf(ftpUser)) }
- .createServer()
-
- private class StaticFtpUserManager(users: List) : UserManager {
- private val userMap: Map = users.map { it.name to it }.toMap()
- override fun getUserByName(username: String?): User? = userMap[username]
- override fun getAllUserNames(): Array = userMap.keys.toTypedArray()
- override fun doesExist(username: String?): Boolean = username in userMap
- override fun delete(username: String?) = throw UnsupportedOperationException()
- override fun save(user: User?) = throw UnsupportedOperationException()
- override fun getAdminName(): String = throw UnsupportedOperationException()
- override fun isAdmin(username: String?): Boolean = throw UnsupportedOperationException()
- override fun authenticate(authentication: Authentication?): User = when (authentication) {
- is UsernamePasswordAuthentication -> getUserByName(authentication.username).let {
- if (it != null && authentication.password == it.password) it
- else throw AuthenticationFailedException()
- }
- else -> throw IllegalArgumentException()
- }
- }
-
- private data class StaticFtpUser(
- private val name: String,
- private val password: String,
- private val homeDirectory: String,
- private val authorities: List
- ) : User {
- override fun getName(): String = name
- override fun getPassword(): String = password
- override fun getAuthorities(): List = authorities
- override fun getAuthorities(clazz: Class): List = authorities.filter(clazz::isInstance)
- override fun getMaxIdleTime(): Int = 0 // unlimited
- override fun getEnabled(): Boolean = true
- override fun getHomeDirectory(): String = homeDirectory
- override fun authorize(request: AuthorizationRequest?): AuthorizationRequest? =
- authorities.filter { it.canAuthorize(request) }.fold(request) { req, auth -> auth.authorize(req) }
- }
-
- /**
- * This registers package loggers filtering the output of the Mina FtpServer.
- * The object holds static references to those loggers so that they stay around.
- */
- private class MinaLoggerOverrider(logLevel: Level) {
- @Suppress("unused")
- private val ftpServerLogger = forceLogLevel("org.apache.ftpserver", logLevel)
-
- @Suppress("unused")
- private val minaLogger = forceLogLevel("org.apache.mina", logLevel)
-
- private fun forceLogLevel(pkgName: String, logLevel: Level) =
- (LoggerFactory.getLogger(pkgName) as Logger).apply { level = logLevel }
- }
-}
diff --git a/app/src/main/res/layout/configure_activity.xml b/app/src/main/res/layout/configure_activity.xml
index 08f29af..5d796fb 100644
--- a/app/src/main/res/layout/configure_activity.xml
+++ b/app/src/main/res/layout/configure_activity.xml
@@ -2,7 +2,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml
index 260caaa..1adbe0f 100644
--- a/app/src/main/res/values-ru-rRU/strings.xml
+++ b/app/src/main/res/values-ru-rRU/strings.xml
@@ -57,7 +57,6 @@
Ошибки
Открыть руководство
Не удалось запустить tinc
- Не удалось запустить FTP-сервер
Не удалось прочитать закрытые ключи tinc:\n%1$s
Не удалось прочитать конфигурацию сетевого интерфейса:\n%1$s
Не удалось привязать сетевой интерфейс. Запущен другой VPN?
@@ -70,10 +69,6 @@
Недопустимая конфигурация сети в network.conf:\n%1$s
Не удалось расшифровать закрытые ключи:\n%1$s
- Доступ к конфигурации
- Сервер доступа к конфигурации активен
- Каталог конфигурации доступен через FTP.
-
Конфигурировать
Трафик с этого устройства будет частично или полностью перенаправляться в выбранную сеть и через нее в соответствии с вашей конфигурацией. Никогда не подключайтесь к сети tinc, которой вы не доверяете.
@@ -85,11 +80,6 @@
Недопустимое имя сети.
Записана конфигурация сети.
- Доступ к конфигурации
- Доступ по FTP
- Пользователь: %1$s, пароль: %2$s, порт: %3$d
- Не активный
-
Информация о внутренних путях
Каталог конфигурации
Каталог журналов
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e124055..c4384a7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -62,7 +62,6 @@
Errors
Open manual
Could not start tinc
- Could not start FTP server
Could not read private tinc keys:\n%1$s
Could not read network interface configuration:\n%1$s
Could not bind network interface. Is another VPN running?
@@ -75,10 +74,6 @@
Invalid network configuration in network.conf:\n%1$s
Could not decrypt private keys:\n%1$s
- Configuration access
- Configuration access server active
- The configuration directory is accessible through FTP.
-
Configure
Traffic from this device will be partially or fully routed to and through the selected network in accordance with your configuration. Never connect to a tinc network which you do not trust.
@@ -90,11 +85,6 @@
Invalid network name.
Network configuration written.
- Configuration access
- FTP access
- User: %1$s, password: %2$s, port: %3$d
- Not active
-
Internal paths info
Configuration directory
Log directory
diff --git a/readme.md b/readme.md
index 853ae62..378337f 100644
--- a/readme.md
+++ b/readme.md
@@ -61,7 +61,6 @@ Builds of this software embed and make use of the following libraries:
* logback-android, licensed under the GNU Lesser General Public License v2.1
* Apache Commons Configuration, licensed under the Apache v2.0 License
* Apache Commons BeanUtils, licensed under the Apache v2.0 License
-* Apache Mina FtpServer, licensed under the Apache v2.0 License
* LZO, licensed under the GNU General Public License v2.0
* LibreSSL libcrypto, licensed under the OpenSSL License, ISC License, public
domain
--
cgit v1.2.3