diff options
Diffstat (limited to 'ipscrambling/src')
-rw-r--r-- | ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt | 2 | ||||
-rw-r--r-- | ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/OrbotServiceSupervisor.kt (renamed from ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/IpScramblerModule.kt) | 132 |
2 files changed, 67 insertions, 67 deletions
diff --git a/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt index bfb9b32..79aeb05 100644 --- a/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt +++ b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/KoinModule.kt @@ -21,5 +21,5 @@ import org.koin.core.module.dsl.singleOf import org.koin.dsl.module val ipScramblerModule = module { - singleOf(::IpScramblerModule) + singleOf(::OrbotServiceSupervisor) } diff --git a/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/IpScramblerModule.kt b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/OrbotServiceSupervisor.kt index d1f01a0..8813948 100644 --- a/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/IpScramblerModule.kt +++ b/ipscrambling/src/main/java/foundation/e/advancedprivacy/ipscrambler/OrbotServiceSupervisor.kt @@ -1,4 +1,5 @@ /* + * Copyright (C) 2023 MURENA SAS * Copyright (C) 2021 E FOUNDATION * * This program is free software: you can redistribute it and/or modify @@ -27,28 +28,37 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import android.os.Message -import android.util.Log import androidx.localbroadcastmanager.content.LocalBroadcastManager +import foundation.e.advancedprivacy.domain.entities.FeatureServiceState +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.pcap4j.packet.DnsPacket import org.torproject.android.service.OrbotConstants import org.torproject.android.service.OrbotConstants.ACTION_STOP_FOREGROUND_TASK import org.torproject.android.service.OrbotService import org.torproject.android.service.util.Prefs +import timber.log.Timber import java.security.InvalidParameterException +import java.util.function.Function @SuppressLint("CommitPrefEdits") -class IpScramblerModule(private val context: Context) { - interface Listener { - fun onStatusChanged(newStatus: Status) - fun log(message: String) - fun onTrafficUpdate(upload: Long, download: Long, read: Long, write: Long) - } +class OrbotServiceSupervisor( + private val context: Context, + private val coroutineScope: CoroutineScope, +) { + private val _state = MutableStateFlow(FeatureServiceState.OFF) + val state: StateFlow<FeatureServiceState> = _state enum class Status { OFF, ON, STARTING, STOPPING, START_DISABLED } companion object { - const val TAG = "IpScramblerModule" - private val EXIT_COUNTRY_CODES = setOf("DE", "AT", "SE", "CH", "IS", "CA", "US", "ES", "FR", "BG", "PL", "AU", "BR", "CZ", "DK", "FI", "GB", "HU", "NL", "JP", "RO", "RU", "SG", "SK") // Key where exit country is stored by orbot service. @@ -58,7 +68,6 @@ class IpScramblerModule(private val context: Context) { } private var currentStatus: Status? = null - private val listeners = mutableSetOf<Listener>() private val localBroadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -70,7 +79,7 @@ class IpScramblerModule(private val context: Context) { currentStatus = newStatus } } catch (e: Exception) { - Log.e(TAG, "Can't parse Orbot service status.") + Timber.e("Can't parse Orbot service status.") } return } @@ -87,18 +96,6 @@ class IpScramblerModule(private val context: Context) { val action = msg.obj as? String ?: return val data = msg.data when (action) { - OrbotConstants.LOCAL_ACTION_LOG -> - data.getString(OrbotConstants.LOCAL_EXTRA_LOG)?.let { newLog(it) } - - OrbotConstants.LOCAL_ACTION_BANDWIDTH -> { - trafficUpdate( - data.getLong("up", 0), - data.getLong("down", 0), - data.getLong("written", 0), - data.getLong("read", 0) - ) - } - OrbotConstants.LOCAL_ACTION_PORTS -> { httpProxyPort = data.getInt(OrbotService.EXTRA_HTTP_PROXY_PORT, -1) socksProxyPort = data.getInt(OrbotService.EXTRA_SOCKS_PROXY_PORT, -1) @@ -110,9 +107,11 @@ class IpScramblerModule(private val context: Context) { val newStatus = Status.valueOf(it) updateStatus(newStatus, force = true) } catch (e: Exception) { - Log.e(TAG, "Can't parse Orbot service status.") + Timber.e("Can't parse Orbot service status.") } } + OrbotConstants.LOCAL_ACTION_LOG, + OrbotConstants.LOCAL_ACTION_BANDWIDTH -> {} // Unused in Advanced Privacy } super.handleMessage(msg) } @@ -150,9 +149,24 @@ class IpScramblerModule(private val context: Context) { private fun updateStatus(status: Status, force: Boolean = false) { if (force || status != currentStatus) { - currentStatus = status - listeners.forEach { - it.onStatusChanged(status) + val newState = when (status) { + Status.OFF -> FeatureServiceState.OFF + Status.ON -> FeatureServiceState.ON + Status.STARTING -> FeatureServiceState.STARTING + Status.STOPPING, + Status.START_DISABLED -> FeatureServiceState.STOPPING + } + + coroutineScope.launch(Dispatchers.IO) { + _state.update { currentState -> + if (newState == FeatureServiceState.OFF && + currentState == FeatureServiceState.STOPPING + ) { + // Wait for orbot to relax before allowing user to reactivate it. + delay(1000) + } + newState + } } } } @@ -165,14 +179,6 @@ class IpScramblerModule(private val context: Context) { return currentStatus != Status.OFF } - private fun newLog(message: String) { - listeners.forEach { it.log(message) } - } - - private fun trafficUpdate(upload: Long, download: Long, read: Long, write: Long) { - listeners.forEach { it.onTrafficUpdate(upload, download, read, write) } - } - private fun sendIntentToService(action: String, extra: Bundle? = null) { val intent = Intent(context, OrbotService::class.java) intent.action = action @@ -203,27 +209,29 @@ class IpScramblerModule(private val context: Context) { } @SuppressLint("ApplySharedPref") - private fun setExitCountryCode(countryCode: String) { - val countryParam = when { - countryCode.isEmpty() -> "" - countryCode in EXIT_COUNTRY_CODES -> "{$countryCode}" - else -> throw InvalidParameterException( - "Only these countries are available: ${EXIT_COUNTRY_CODES.joinToString { ", " } }" - ) - } + suspend fun setExitCountryCode(countryCode: String) { + withContext(Dispatchers.IO) { + val countryParam = when { + countryCode.isEmpty() -> "" + countryCode in EXIT_COUNTRY_CODES -> "{$countryCode}" + else -> throw InvalidParameterException( + "Only these countries are available: ${EXIT_COUNTRY_CODES.joinToString { ", " }}" + ) + } - if (isServiceRunning()) { - val extra = Bundle() - extra.putString("exit", countryParam) - sendIntentToService(OrbotConstants.CMD_SET_EXIT, extra) - } else { - Prefs.getSharedPrefs(context) - .edit().putString(PREFS_KEY_EXIT_NODES, countryParam) - .commit() + if (isServiceRunning()) { + val extra = Bundle() + extra.putString("exit", countryParam) + sendIntentToService(OrbotConstants.CMD_SET_EXIT, extra) + } else { + Prefs.getSharedPrefs(context) + .edit().putString(PREFS_KEY_EXIT_NODES, countryParam) + .commit() + } } } - private fun getExitCountryCode(): String { + fun getExitCountryCode(): String { val raw = Prefs.getExitNodes() return if (raw.isEmpty()) raw else raw.slice(1..2) } @@ -232,6 +240,10 @@ class IpScramblerModule(private val context: Context) { return VpnService.prepare(context) } + fun setDNSFilter(shouldBlock: Function<DnsPacket?, DnsPacket?>?) { + OrbotService.shouldBlock = shouldBlock + } + fun start(enableNotification: Boolean) { Prefs.enableNotification(enableNotification) Prefs.putUseVpn(true) @@ -242,6 +254,8 @@ class IpScramblerModule(private val context: Context) { } fun stop() { + if (!isServiceRunning()) return + updateStatus(Status.STOPPING) Prefs.putUseVpn(false) @@ -280,10 +294,6 @@ class IpScramblerModule(private val context: Context) { get() = getTorifiedApps() set(value) = saveTorifiedApps(value) - var exitCountry: String - get() = getExitCountryCode() - set(value) = setExitCountryCode(value) - fun getAvailablesLocations(): Set<String> = EXIT_COUNTRY_CODES var httpProxyPort: Int = -1 @@ -292,16 +302,6 @@ class IpScramblerModule(private val context: Context) { var socksProxyPort: Int = -1 private set - fun addListener(listener: Listener) { - listeners.add(listener) - } - fun removeListener(listener: Listener) { - listeners.remove(listener) - } - fun clearListeners() { - listeners.clear() - } - fun onCleared() { LocalBroadcastManager.getInstance(context).unregisterReceiver(localBroadcastReceiver) } |