summaryrefslogtreecommitdiff
path: root/trackersservicestandalone
diff options
context:
space:
mode:
authorGuillaume Jacquart <guillaume.jacquart@hoodbrains.com>2023-11-06 08:14:27 +0000
committerGuillaume Jacquart <guillaume.jacquart@hoodbrains.com>2023-11-06 08:14:27 +0000
commit9d55978063947d5865bb3fa4e0c2ebef78f78812 (patch)
tree49a07707f82375dc9d5d1048a07bbdf866bffe67 /trackersservicestandalone
parent0312ce64f85b5530a00bdc72eb310ba9dc1de05b (diff)
epic18: Manage VPN services for Tor or Tracker control
Diffstat (limited to 'trackersservicestandalone')
-rw-r--r--trackersservicestandalone/build.gradle1
-rw-r--r--trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersService.kt21
-rw-r--r--trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersSupervisorStandalone.kt (renamed from trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersServiceSupervisorImpl.kt)30
-rw-r--r--trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TunLooper.kt1
-rw-r--r--trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/usecases/VpnSupervisorUseCaseStandalone.kt154
5 files changed, 181 insertions, 26 deletions
diff --git a/trackersservicestandalone/build.gradle b/trackersservicestandalone/build.gradle
index ead9dbd..5b574cd 100644
--- a/trackersservicestandalone/build.gradle
+++ b/trackersservicestandalone/build.gradle
@@ -29,6 +29,7 @@ android {
dependencies {
implementation project(":core")
implementation project(":trackers")
+ implementation project(":ipscrambling")
implementation(
libs.androidx.core.ktx,
diff --git a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersService.kt b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersService.kt
index 918977f..152a3e9 100644
--- a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersService.kt
+++ b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersService.kt
@@ -16,16 +16,15 @@
*/
package foundation.e.advancedprivacy.trackers.service
-import android.content.Context
import android.content.Intent
import android.net.VpnService
import android.os.Build
import android.os.ParcelFileDescriptor
import foundation.e.advancedprivacy.core.utils.notificationBuilder
-import foundation.e.advancedprivacy.domain.entities.FeatureServiceState
+import foundation.e.advancedprivacy.domain.entities.FeatureState
import foundation.e.advancedprivacy.domain.entities.NOTIFICATION_TRACKER_FLAG
import foundation.e.advancedprivacy.domain.entities.NotificationContent
-import foundation.e.advancedprivacy.trackers.domain.externalinterfaces.TrackersServiceSupervisor
+import foundation.e.advancedprivacy.trackers.domain.externalinterfaces.TrackersSupervisor
import foundation.e.advancedprivacy.trackers.service.Config.DNS_SERVER_TO_CATCH_IPV4
import foundation.e.advancedprivacy.trackers.service.Config.DNS_SERVER_TO_CATCH_IPV6
import foundation.e.advancedprivacy.trackers.service.Config.SESSION_NAME
@@ -39,18 +38,12 @@ import timber.log.Timber
class TrackersService : VpnService() {
companion object {
var coroutineScope = CoroutineScope(Dispatchers.IO)
-
- fun start(context: Context) {
- prepare(context)
- val intent = Intent(context, TrackersService::class.java)
- context.startService(intent)
- }
}
private val networkDNSAddressRepository: NetworkDNSAddressRepository = get(NetworkDNSAddressRepository::class.java)
- private val trackersServiceSupervisor: TrackersServiceSupervisorImpl = get(
- TrackersServiceSupervisor::class.java
- ) as TrackersServiceSupervisorImpl
+ private val trackersSupervisor: TrackersSupervisorStandalone = get(
+ TrackersSupervisor::class.java
+ ) as TrackersSupervisorStandalone
private val notificationTrackerFlag: NotificationContent = get(NotificationContent::class.java, named("notificationTrackerFlag"))
@@ -64,14 +57,14 @@ class TrackersService : VpnService() {
content = notificationTrackerFlag
).build()
)
- trackersServiceSupervisor.state.value = FeatureServiceState.ON
+ trackersSupervisor.mutableState.value = FeatureState.ON
return START_STICKY
}
override fun onDestroy() {
networkDNSAddressRepository.stop()
- trackersServiceSupervisor.state.value = FeatureServiceState.OFF
+ trackersSupervisor.mutableState.value = FeatureState.OFF
super.onDestroy()
}
diff --git a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersServiceSupervisorImpl.kt b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersSupervisorStandalone.kt
index e2a6692..ac06ced 100644
--- a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersServiceSupervisorImpl.kt
+++ b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TrackersSupervisorStandalone.kt
@@ -18,37 +18,42 @@ package foundation.e.advancedprivacy.trackers.service
import android.content.Context
import android.content.Intent
-import foundation.e.advancedprivacy.domain.entities.FeatureServiceState
-import foundation.e.advancedprivacy.trackers.domain.externalinterfaces.TrackersServiceSupervisor
+import foundation.e.advancedprivacy.domain.entities.FeatureState
+import foundation.e.advancedprivacy.domain.usecases.VpnSupervisorUseCase
+import foundation.e.advancedprivacy.trackers.domain.externalinterfaces.TrackersSupervisor
import foundation.e.advancedprivacy.trackers.service.data.NetworkDNSAddressRepository
import foundation.e.advancedprivacy.trackers.service.data.RequestDNSRepository
import foundation.e.advancedprivacy.trackers.service.usecases.ResolveDNSUseCase
+import foundation.e.advancedprivacy.trackers.service.usecases.VpnSupervisorUseCaseStandalone
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
import org.pcap4j.packet.DnsPacket
import java.util.function.Function
-class TrackersServiceSupervisorImpl(
+class TrackersSupervisorStandalone(
private val context: Context,
private val resolveDNSUseCase: ResolveDNSUseCase
-) : TrackersServiceSupervisor {
- internal val state: MutableStateFlow<FeatureServiceState> = MutableStateFlow(FeatureServiceState.OFF)
+) : TrackersSupervisor {
+ internal val mutableState: MutableStateFlow<FeatureState> = MutableStateFlow(FeatureState.OFF)
+ override val state: StateFlow<FeatureState> = mutableState
override fun start(): Boolean {
return if (!isRunning()) {
- state.value = FeatureServiceState.STARTING
- TrackersService.start(context)
+ mutableState.value = FeatureState.STARTING
+ val intent = Intent(context, TrackersService::class.java)
+ context.startService(intent)
true
} else false
}
override fun stop(): Boolean {
- return when (state.value) {
- FeatureServiceState.ON -> {
- state.value = FeatureServiceState.STOPPING
+ return when (mutableState.value) {
+ FeatureState.ON -> {
+ mutableState.value = FeatureState.STOPPING
kotlin.runCatching { TrackersService.coroutineScope.cancel() }
context.stopService(Intent(context, TrackersService::class.java))
true
@@ -58,7 +63,7 @@ class TrackersServiceSupervisorImpl(
}
override fun isRunning(): Boolean {
- return state.value != FeatureServiceState.OFF
+ return state.value != FeatureState.OFF
}
override val dnsFilterForIpScrambling = Function<DnsPacket?, DnsPacket?> { dnsRequest -> resolveDNSUseCase.shouldBlock(dnsRequest) }
@@ -69,5 +74,6 @@ val trackerServiceModule = module {
singleOf(::RequestDNSRepository)
singleOf(::ResolveDNSUseCase)
singleOf(::TunLooper)
- singleOf(::TrackersServiceSupervisorImpl) { bind<TrackersServiceSupervisor>() }
+ singleOf(::TrackersSupervisorStandalone) { bind<TrackersSupervisor>() }
+ singleOf(::VpnSupervisorUseCaseStandalone) { bind<VpnSupervisorUseCase>() }
}
diff --git a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TunLooper.kt b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TunLooper.kt
index 7813c67..bb349eb 100644
--- a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TunLooper.kt
+++ b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/TunLooper.kt
@@ -84,6 +84,7 @@ class TunLooper(
}
}
}
+ closeStreams()
}
private suspend fun handleIpPacket(buffer: ByteArray, pLen: Int) {
diff --git a/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/usecases/VpnSupervisorUseCaseStandalone.kt b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/usecases/VpnSupervisorUseCaseStandalone.kt
new file mode 100644
index 0000000..683f886
--- /dev/null
+++ b/trackersservicestandalone/src/main/java/foundation/e/advancedprivacy/trackers/service/usecases/VpnSupervisorUseCaseStandalone.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 MURENA SAS
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+package foundation.e.advancedprivacy.trackers.service.usecases
+
+import foundation.e.advancedprivacy.domain.entities.FeatureState
+import foundation.e.advancedprivacy.domain.entities.MainFeatures
+import foundation.e.advancedprivacy.domain.entities.MainFeatures.IpScrambling
+import foundation.e.advancedprivacy.domain.entities.MainFeatures.TrackersControl
+import foundation.e.advancedprivacy.domain.repositories.LocalStateRepository
+import foundation.e.advancedprivacy.domain.usecases.VpnSupervisorUseCase
+import foundation.e.advancedprivacy.externalinterfaces.servicesupervisors.FeatureSupervisor
+import foundation.e.advancedprivacy.ipscrambler.OrbotSupervisor
+import foundation.e.advancedprivacy.trackers.domain.externalinterfaces.TrackersSupervisor
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.launch
+
+class VpnSupervisorUseCaseStandalone(
+ private val localStateRepository: LocalStateRepository,
+ private val trackersSupervisor: TrackersSupervisor,
+ private val orbotSupervisor: OrbotSupervisor,
+ private val scope: CoroutineScope,
+) : VpnSupervisorUseCase {
+ private var applySettingJob: Job? = null
+
+ init {
+ listenSettings()
+ }
+
+ override fun listenSettings() {
+ var previousBlockTrackers: Boolean? = null
+
+ localStateRepository.blockTrackers.combine(
+ localStateRepository.ipScramblingSetting
+ ) { blockTrackers, hideIp ->
+ applySettingJob?.cancel()
+ applySettingJob = scope.launch {
+ when {
+ blockTrackers && !hideIp ->
+ launchVpnService(trackersSupervisor)
+
+ !blockTrackers && !hideIp ->
+ stopAllServices()
+
+ else -> {
+ if (blockTrackers && previousBlockTrackers != true) {
+ localStateRepository.emitStartVpnDisclaimer(IpScrambling())
+ }
+
+ launchVpnService(orbotSupervisor)
+ }
+ }
+
+ previousBlockTrackers = blockTrackers
+ }
+ }.launchIn(scope)
+ }
+
+ private fun stopAllServices() {
+ listOf(orbotSupervisor, trackersSupervisor).map { stopVpnService(it) }
+ }
+
+ private fun stopVpnService(supervisor: FeatureSupervisor): FeatureSupervisor {
+ when (supervisor.state.value) {
+ FeatureState.ON,
+ FeatureState.STARTING ->
+ supervisor.stop()
+
+ else -> {}
+ }
+ return supervisor
+ }
+
+ private suspend fun launchVpnService(supervisor: FeatureSupervisor) {
+ stopVpnService(otherSupervisor(supervisor)).let { otherSupervisor ->
+ otherSupervisor.state.first { it == FeatureState.OFF }
+ }
+
+ when (supervisor.state.value) {
+ FeatureState.STOPPING -> {
+ supervisor.state.first { it == FeatureState.OFF }
+ initiateStartVpnService(supervisor)
+ }
+
+ FeatureState.OFF -> initiateStartVpnService(supervisor)
+ else -> {}
+ }
+ }
+
+ private fun otherSupervisor(supervisor: FeatureSupervisor): FeatureSupervisor {
+ return when (supervisor) {
+ trackersSupervisor -> orbotSupervisor
+ else -> trackersSupervisor
+ }
+ }
+
+ private fun getSupervisor(feature: MainFeatures): FeatureSupervisor {
+ return when (feature) {
+ is TrackersControl -> trackersSupervisor
+ else -> orbotSupervisor
+ }
+ }
+
+ private suspend fun initiateStartVpnService(supervisor: FeatureSupervisor) {
+ val authorizeVpnIntent = orbotSupervisor.prepareAndroidVpn()
+ val feature = when (supervisor) {
+ trackersSupervisor -> TrackersControl(authorizeVpnIntent)
+ else -> IpScrambling(authorizeVpnIntent)
+ }
+
+ if (authorizeVpnIntent == null) {
+ localStateRepository.emitStartVpnDisclaimer(feature)
+ startVpnService(feature)
+ } else {
+ localStateRepository.emitStartVpnDisclaimer(feature)
+ }
+ }
+
+ override fun startVpnService(feature: MainFeatures) {
+ if (feature is IpScrambling) {
+ localStateRepository.internetPrivacyMode.value = FeatureState.STARTING
+ orbotSupervisor.setDNSFilter(trackersSupervisor.dnsFilterForIpScrambling)
+ }
+
+ getSupervisor(feature).start()
+ }
+
+ override fun cancelStartVpnService(feature: MainFeatures) {
+ when (feature) {
+ is IpScrambling ->
+ localStateRepository.setIpScramblingSetting(enabled = false)
+ is TrackersControl ->
+ trackersSupervisor.stop()
+ else -> {}
+ }
+ }
+}