Skip to content
This repository was archived by the owner on Dec 18, 2022. It is now read-only.

Commit 0c200df

Browse files
authored
Merge pull request #4 from 05nelsonm/mn/feature/register-multiple-jtorctl-listeners
Adds ability to register multiple jtorctl listeners to the TorControlConnection
2 parents 65b180a + 101e009 commit 0c200df

File tree

5 files changed

+85
-23
lines changed

5 files changed

+85
-23
lines changed

gradle/dependencies.gradle

+3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ ext.deps = [
1919
],
2020
],
2121
gradleVersions: "com.github.ben-manes:gradle-versions-plugin:0.20.0",
22+
23+
// Update TorServiceController.Builder documentation if bumping versions.
2224
jtorctl: "info.guardianproject:jtorctl:0.4",
25+
2326
junit: "junit:junit:4.12",
2427
kotlin: [
2528
coroutinesCore: "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6",

topl-core/src/main/java/io/matthewnelson/topl_core/OnionProxyManager.kt

+27-5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import io.matthewnelson.topl_core.util.OnionProxyConsts.ConfigFile
4141
import io.matthewnelson.topl_core.util.FileUtilities
4242
import io.matthewnelson.topl_core.util.WriteObserver
4343
import io.matthewnelson.topl_core_base.TorStates
44+
import net.freehaven.tor.control.EventListener
4445
import net.freehaven.tor.control.TorControlCommands
4546
import net.freehaven.tor.control.TorControlConnection
4647
import org.slf4j.Logger
@@ -61,20 +62,22 @@ import java.util.concurrent.TimeUnit
6162
*
6263
* This class began life as TorPlugin from the Briar Project
6364
*
64-
* @param [context] Context
65+
* @param [context] Context.
6566
* @param [onionProxyContext] [OnionProxyContext]
66-
* @param [eventBroadcaster] [EventBroadcaster]? will fallback to defaults if null
67-
* @param [baseEventListener] [BaseEventListener]? will fallback to defaults if null
67+
* @param [eventBroadcaster] [EventBroadcaster]? will fallback to defaults if null.
68+
* @param [primaryEventListener] [BaseEventListener]? will fallback to defaults if null.
69+
* @param [additionalEventListeners] Array<[EventListener]?>? add additional listeners at Tor [start].
6870
*/
6971
class OnionProxyManager(
7072
private val context: Context,
7173
val onionProxyContext: OnionProxyContext,
7274
eventBroadcaster: EventBroadcaster?,
73-
baseEventListener: BaseEventListener?
75+
primaryEventListener: BaseEventListener?,
76+
private val additionalEventListeners: Array<EventListener?>?
7477
): TorStates() {
7578

7679
val eventBroadcaster = eventBroadcaster ?: DefaultEventBroadcaster(onionProxyContext.torSettings)
77-
private val eventListener = baseEventListener ?: DefaultEventListener()
80+
private val eventListener = primaryEventListener ?: DefaultEventListener()
7881

7982
private companion object {
8083
const val OWNER = "__OwningControllerProcess"
@@ -250,6 +253,17 @@ class OnionProxyManager(
250253
} catch (eeee: IOException) {}
251254

252255
} finally {
256+
257+
try {
258+
controlConnection!!.removeRawEventListener(eventListener)
259+
if (!additionalEventListeners.isNullOrEmpty())
260+
additionalEventListeners.forEach { listener ->
261+
listener?.let {
262+
controlConnection!!.removeRawEventListener(it)
263+
}
264+
}
265+
} catch (e: KotlinNullPointerException) {}
266+
253267
controlConnection = null
254268
if (controlSocket != null) {
255269
try {
@@ -431,7 +445,15 @@ class OnionProxyManager(
431445

432446
if (eventListener.CONTROL_COMMAND_EVENTS.isNotEmpty()) {
433447
eventBroadcaster.broadcastNotice("adding control port event listener")
448+
434449
controlConnection.addRawEventListener(eventListener)
450+
if (!additionalEventListeners.isNullOrEmpty())
451+
additionalEventListeners.forEach { listener ->
452+
listener?.let {
453+
controlConnection.addRawEventListener(it)
454+
}
455+
}
456+
435457
controlConnection.setEvents(listOf(*eventListener.CONTROL_COMMAND_EVENTS))
436458
eventBroadcaster.broadcastNotice("SUCCESS added control port event listener")
437459
}

topl-service/src/main/java/io/matthewnelson/topl_service/TorServiceController.kt

+28
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import io.matthewnelson.topl_service.service.ActionConsts.ServiceAction
1212
import androidx.core.app.NotificationCompat.NotificationVisibility
1313
import io.matthewnelson.topl_core_base.TorConfigFiles
1414
import io.matthewnelson.topl_core_base.TorSettings
15+
import net.freehaven.tor.control.EventListener
1516

1617
class TorServiceController private constructor() {
1718

@@ -57,6 +58,7 @@ class TorServiceController private constructor() {
5758
) {
5859

5960
private lateinit var torConfigFiles: TorConfigFiles
61+
private lateinit var additionalEventListener: EventListener
6062

6163
/**
6264
* If you wish to customize the file structure of how Tor is installed in your app,
@@ -77,6 +79,26 @@ class TorServiceController private constructor() {
7779
return this
7880
}
7981

82+
/**
83+
* This will require adding the `jtorctl` library:
84+
*
85+
* - Add `implementation "info.guardianproject:jtorctl:0.4"` to your dependencies block
86+
*
87+
* Extend the [EventListener] class and implement the overridden methods. It will be
88+
* registered when Tor is started up so messages from Tor will be piped to it.
89+
*
90+
* This is limited to adding only 1 event listener. Also, see which
91+
*
92+
* See [io.matthewnelson.topl_service.onionproxy.OnionProxyEventListener] for an example
93+
* and what `CONTROL_COMMAND_EVENTS` will be registered to be listened for.
94+
*
95+
* @param [jtorctlEventListener] [EventListener]
96+
* */
97+
fun addTorEventListener(jtorctlEventListener: EventListener): Builder {
98+
this.additionalEventListener = jtorctlEventListener
99+
return this
100+
}
101+
80102
/**
81103
* Customize the service notification to your application.
82104
*
@@ -302,10 +324,16 @@ class TorServiceController private constructor() {
302324
} else {
303325
TorConfigFiles.createConfig(context.applicationContext)
304326
}
327+
val eventListener =
328+
if (::additionalEventListener.isInitialized)
329+
this.additionalEventListener
330+
else
331+
null
305332

306333
TorService.initialize(
307334
torConfigFiles,
308335
torSettings,
336+
eventListener,
309337
buildConfigVersion,
310338
geoipAssetPath,
311339
geoip6AssetPath

topl-service/src/main/java/io/matthewnelson/topl_service/onionproxy/OnionProxyInstaller.kt

+8-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import java.util.concurrent.TimeoutException
1717
*
1818
* @param [torService] for context.
1919
* @param [torConfigFiles] [TorConfigFiles] to know where files/directories are.
20-
* @param [appVersionCode] Mitigate copying of geoip files to app updates only. Use [BuildConfig.VERSION_CODE].
20+
* @param [buildConfigVersionCode] Mitigate copying of geoip files to app updates only. Use [BuildConfig.VERSION_CODE].
2121
* @param [geoIpAssetPath] The path to geoip file within the application, ex: "common/geoip"
2222
* @param [geoIp6AssetPath] The path to geoip6 file within the application, ex: "common/geoip6"
2323
*
@@ -26,7 +26,7 @@ import java.util.concurrent.TimeoutException
2626
internal class OnionProxyInstaller(
2727
private val torService: TorService,
2828
private val torConfigFiles: TorConfigFiles,
29-
private val appVersionCode: Int,
29+
private val buildConfigVersionCode: Int,
3030
private val geoIpAssetPath: String,
3131
private val geoIp6AssetPath: String
3232
): TorInstaller() {
@@ -45,13 +45,16 @@ internal class OnionProxyInstaller(
4545
geoIp6FileCoppied = ""
4646

4747
// If the app version has been increased, or if this is a debug build of topl-service
48-
// module, copy over geoip assets then update SharedPreferences with the new appVersion
49-
if (appVersionCode > prefs.getInt("APP_VERSION", -1) ?: -1 || BuildConfig.DEBUG) {
48+
// module, copy over geoip assets then update SharedPreferences with the updated
49+
// version code. Mitigates copying to be done only if a version upgrade is had.
50+
if (buildConfigVersionCode > prefs.getInt("BUILD_CONFIG_VERSION_CODE", -1) ?: -1 ||
51+
BuildConfig.DEBUG
52+
) {
5053
if (!::geoIpFileCoppied.isInitialized)
5154
copyAsset(geoIpAssetPath, torConfigFiles.geoIpFile)
5255
if (!::geoIp6FileCoppied.isInitialized)
5356
copyAsset(geoIp6AssetPath, torConfigFiles.geoIpv6File)
54-
prefs.putInt("APP_VERSION", appVersionCode)
57+
prefs.putInt("BUILD_CONFIG_VERSION_CODE", buildConfigVersionCode)
5558
}
5659
}
5760

topl-service/src/main/java/io/matthewnelson/topl_service/service/TorService.kt

+19-13
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,32 @@ import io.matthewnelson.topl_service.onionproxy.OnionProxyEventBroadcaster
1616
import io.matthewnelson.topl_service.onionproxy.OnionProxyEventListener
1717
import io.matthewnelson.topl_service.onionproxy.OnionProxyInstaller
1818
import io.matthewnelson.topl_service.service.ActionConsts.ServiceAction
19+
import net.freehaven.tor.control.EventListener
1920

2021
internal class TorService: Service() {
2122

2223
companion object {
2324
private lateinit var torConfigFiles: TorConfigFiles
2425
private lateinit var torSettings: TorSettings
25-
private var buildConfigVersion: Int = -1
26+
private var additionalEventListener: EventListener? = null
27+
private var buildConfigVersionCode: Int = -1
2628
private lateinit var geoipAssetPath: String
2729
private lateinit var geoip6AssetPath: String
2830

2931
fun initialize(
30-
config: TorConfigFiles,
31-
settings: TorSettings,
32-
buildVersion: Int,
33-
geoipPath: String,
34-
geoip6Path: String
32+
torConfigFiles: TorConfigFiles,
33+
torSettings: TorSettings,
34+
additionalEventListener: EventListener?,
35+
buildConfigVersionCode: Int,
36+
geoipAssetPath: String,
37+
geoip6AssetPath: String
3538
) {
36-
torConfigFiles = config
37-
torSettings = settings
38-
buildConfigVersion = buildVersion
39-
geoipAssetPath = geoipPath
40-
geoip6AssetPath = geoip6Path
39+
this.torConfigFiles = torConfigFiles
40+
this.torSettings = torSettings
41+
this.additionalEventListener = additionalEventListener
42+
this.buildConfigVersionCode = buildConfigVersionCode
43+
this.geoipAssetPath = geoipAssetPath
44+
this.geoip6AssetPath = geoip6AssetPath
4145
}
4246

4347
// Intents/LocalBroadcastManager
@@ -59,7 +63,7 @@ internal class TorService: Service() {
5963
val onionProxyInstaller = OnionProxyInstaller(
6064
this,
6165
torConfigFiles,
62-
buildConfigVersion,
66+
buildConfigVersionCode,
6367
geoipAssetPath,
6468
geoip6AssetPath
6569
)
@@ -69,11 +73,13 @@ internal class TorService: Service() {
6973
torServiceSettings
7074
)
7175
val onionProxyEventBroadcaster = OnionProxyEventBroadcaster(this, torServiceSettings)
76+
val onionProxyEventListener = OnionProxyEventListener(this, onionProxyEventBroadcaster)
7277
onionProxyManager = OnionProxyManager(
7378
this,
7479
onionProxyContext,
7580
onionProxyEventBroadcaster,
76-
OnionProxyEventListener(this, onionProxyEventBroadcaster)
81+
onionProxyEventListener,
82+
arrayOf(additionalEventListener)
7783
)
7884
onionProxyManager.setup()
7985
}

0 commit comments

Comments
 (0)