Tor now listens to port changes and restart connections when it does change.

This commit is contained in:
Vitor Pamplona
2025-03-31 20:32:15 -04:00
parent 491d269f75
commit b3f1b093ed
6 changed files with 44 additions and 15 deletions
@@ -121,7 +121,7 @@ class ServiceManager(
HttpClientManager.setProxyNotReady()
}
}
else -> HttpClientManager.setDefaultProxy(null)
else -> HttpClientManager.setProxyNotReady()
}
OtsResolver.ots =
@@ -136,7 +136,7 @@ class ServiceManager(
OkHttpCalendarBuilder { false },
)
HttpClientManager.setDefaultProxy(null)
HttpClientManager.setProxyNotReady()
}
// Convert this into a flow
@@ -29,6 +29,7 @@ import com.vitorpamplona.amethyst.launchAndWaitAll
import com.vitorpamplona.amethyst.model.AccountSettings
import com.vitorpamplona.amethyst.service.okhttp.HttpClientManager
import com.vitorpamplona.amethyst.tryAndWait
import com.vitorpamplona.amethyst.ui.tor.TorManager
import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent
import com.vitorpamplona.quartz.nip55AndroidSigner.NostrSignerExternal
import kotlinx.coroutines.CancellationException
@@ -151,8 +152,8 @@ class RegisterAccounts(
.post(body)
.build()
// Always try via Tor for Amethyst.
val client = HttpClientManager.getHttpClient(true)
// Always try via Tor if active.
val client = HttpClientManager.getHttpClient(TorManager.isSocksReady())
val isSucess = client.newCall(request).execute().use { it.isSuccessful }
Log.i(tag, "Server registration $isSucess")
@@ -62,6 +62,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginOrSignupScreen
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.tor.TorManager
import com.vitorpamplona.amethyst.ui.tor.TorStatus
import com.vitorpamplona.amethyst.ui.tor.TorType
import com.vitorpamplona.quartz.nip55AndroidSigner.NostrSignerExternal
import kotlinx.coroutines.CancellationException
@@ -160,6 +161,7 @@ fun ManageTorInstance(accountViewModel: AccountViewModel) {
val torSettings by accountViewModel.account.settings.torSettings.torType
.collectAsStateWithLifecycle()
if (torSettings == TorType.INTERNAL) {
WatchConnection(accountViewModel)
ManageTorInstanceInner(accountViewModel)
}
}
@@ -204,6 +206,17 @@ fun ManageTorInstanceInner(accountViewModel: AccountViewModel) {
}
}
@Composable
fun WatchConnection(accountViewModel: AccountViewModel) {
val status by TorManager.status.collectAsStateWithLifecycle()
LaunchedEffect(key1 = status, key2 = accountViewModel) {
if (status is TorStatus.Active) {
accountViewModel.changeProxyPort((status as TorStatus.Active).port)
}
}
}
@Composable
private fun ListenToExternalSignerIfNeeded(accountViewModel: AccountViewModel) {
if (accountViewModel.account.signer is NostrSignerExternal) {
@@ -1265,6 +1265,12 @@ class AccountViewModel(
}
}
fun changeProxyPort(port: Int) {
viewModelScope.launch(Dispatchers.IO) {
Amethyst.instance.serviceManager.forceRestart()
}
}
class Factory(
val accountSettings: AccountSettings,
val settings: SettingsState,
@@ -27,20 +27,33 @@ import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import androidx.appcompat.app.AppCompatActivity.BIND_AUTO_CREATE
import com.vitorpamplona.amethyst.service.okhttp.HttpClientManager
import kotlinx.coroutines.flow.MutableStateFlow
import org.torproject.jni.TorService
import org.torproject.jni.TorService.LocalBinder
import java.util.concurrent.atomic.AtomicBoolean
sealed class TorStatus {
data class Active(
val port: Int,
) : TorStatus()
object Off : TorStatus()
object Connecting : TorStatus()
}
object TorManager {
var runningIntent: Intent? = null
var torService: TorService? = null
val status = MutableStateFlow<TorStatus>(TorStatus.Off)
// To make sure we don't start two services.
var isConnectingMutex = AtomicBoolean(false)
fun startTorIfNotAlreadyOn(ctx: Context) {
if (runningIntent == null && isConnectingMutex.compareAndSet(false, true)) {
status.tryEmit(TorStatus.Connecting)
try {
startTor(ctx)
} finally {
@@ -54,6 +67,7 @@ object TorManager {
runningIntent?.let {
ctx.stopService(runningIntent)
}
status.tryEmit(TorStatus.Off)
runningIntent = null
torService = null
}
@@ -80,14 +94,14 @@ object TorManager {
}
}
HttpClientManager.setDefaultProxyOnPort(socksPort())
status.tryEmit(TorStatus.Active(socksPort()))
Log.d("TorManager", "Tor Service Connected ${socksPort()}")
}
override fun onServiceDisconnected(name: ComponentName) {
runningIntent = null
torService = null
status.tryEmit(TorStatus.Off)
Log.d("TorManager", "Tor Service Disconected")
}
},
@@ -95,10 +109,7 @@ object TorManager {
)
}
fun isSocksReady() =
torService?.let {
it.socksPort > 0
} ?: false
fun isSocksReady() = torService?.let { it.socksPort > 0 } == true
fun socksPort(): Int = torService?.socksPort ?: 9050
@@ -35,6 +35,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.AuthCmd
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.CloseCmd
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.CountCmd
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.EventCmd
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.ReqCmd
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebSocket
import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebSocketListener
@@ -312,10 +313,7 @@ class SimpleClientRelay(
if (isConnectionStarted()) {
if (isReady) {
if (filters.isNotEmpty()) {
writeToSocket(
com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.ReqCmd
.toJson(requestId, filters),
)
writeToSocket(ReqCmd.toJson(requestId, filters))
afterEOSEPerSubscription[requestId] = false
}
}