Git Product home page Git Product logo

kmp-tor's Introduction

kmp-tor

badge-license badge-latest-release

badge-kotlin badge-atomicfu badge-coroutines badge-encoding badge-parcelize badge-kmp-tor-binary

badge-platform-android badge-platform-jvm

Kotlin Multiplatform support for embedding Tor into your application.

NOTICE: kmp-tor is being overhauled. This branch is for the 1.x.x version. See HERE for the latest and greatest.

Get Started

Add dependency

// build.gradle.kts

dependencies {
    val vTor = "4.8.10-0"
    val vKmpTor = "1.4.4"

    implementation("io.matthewnelson.kotlin-components:kmp-tor:$vTor-$vKmpTor")
}
// build.gradle

dependencies {
    def vTor = '4.8.10-0'
    def vKmpTor = '1.4.4'

    implementation "io.matthewnelson.kotlin-components:kmp-tor:$vTor-$vKmpTor"
}
Configuring an Android Project
  • Ensure that the Kotlin Gradle Plugin is applied to your project

  • See the Android section of the kmp-tor-binary project's README to set things up so the Tor binaries are properly extracted upon app install.

  • By default, TorService needs no configuration and runs in the background. For configuring it to run as a Foreground service, see the following:

  • See the Sample App for a basic setup of TorManager and your TorConfig.
Configuring a Java Project
  • See the Java section of the kmp-tor-binary project's README.
  • See the JavaFX Sample App Gradle Configuration for a basic gradle/dependency configuration.
  • See the JavaFx Sample App for a basic setup example.
  • Run the JavaFx Sample via ./gradlew :samples:kotlin:javafx:run -PKMP_TARGETS=JVM from terminal or cmd prompt.
    • Note: Be sure to run git submodule update --init if you haven't yet so git submodules are initialized.

Extensions

Unix Domain Sockets

Tor supports use of unix domain sockets on Darwin and Linux (also Android) for the following:

  • ControlPort
  • SocksPort
  • HiddenServicePort

How to enable unix domain socket support for the ControlPort:

  • For Android, nothing is needed
  • For JVM
    • If JDK 16+, nothing is needed
    • Otherwise, add the following dependency to your darwin/linux builds:
    // build.gradlew.kts
    
    dependencies {
        val vTor = "4.8.10-0"
        val vKmpTor = "1.4.4"
    
        implementation("io.matthewnelson.kotlin-components:kmp-tor:$vTor-$vKmpTor")
    
        if (isLinuxBuild || isDarwinBuild) {
            // Unix Domain Socket support extension (JDK 15 and below)
            implementation("io.matthewnelson.kotlin-components:kmp-tor-ext-unix-socket:$vKmpTor")
        }
    }

See the JavaFX Sample App Gradle Configuration dependencies block for more info.

If neither TorConfig.Setting.Ports.Control or TorConfig.Setting.UnixSockets.Control are expressed in your config, TorConfig.Setting.UnixSockets.Control will always be the preferred setting for establishing a connection to Tor's control port, if support is had (as noted above). To override this behavior, you can express the TorConfig.Setting.Ports.Control setting when providing your config at startup.

How to enable unix domain socket support for the SocksPort and HiddenServicePort settings:

  • Be running on Darwin or Linux (also Android)
Callbacks (non-kotlin consumers)
  • For Java projects (who can't use coroutines), you can "wrap" TorManager in an implementation that uses callbacks (i.e. CallbackTorManager).
// build.gradle

dependencies {
    def vTor = '4.8.10-0'
    def vKmpTor = '1.4.4'

    implementation "io.matthewnelson.kotlin-components:kmp-tor:$vTor-$vKmpTor"
    // Add the callback extension
    implementation "io.matthewnelson.kotlin-components:kmp-tor-ext-callback-manager:$vKmpTor"

    // You will also need to add the Kotlin Gradle Plugin, and Coroutines dependency.
    
    // If not Android, you will also need to import the binaries for the platforms you wish to
    // support.
}
// Wrapping TorManager instance in its Callback instance (Java)
public class Example1 {
    
    // ..
    TorManager instance = TorManager.newInstance(/* ... */);

    // Wrap that mug...
    CallbackTorManager torManager = new CallbackTorManager(
        instance,
        uncaughtException -> {
            Log.e("MyJavaApp", "Some TorCallback isn't handling an exception...", uncaughtException);
        }
     );
}
  • All requests use coroutines under the hood and are Main thread safe. Results will be dispatched to the supplied callback on the Main thread.
// Multiple callbacks of different styles (Java)
public class Example2 {
    
    // ...
    Task startTask = torManager.start(
        t -> Log.e(TAG, "Failed to start Tor", t),
        startSuccess -> {

            Log.d(TAG, "Tor started successfully");

            Task restartTask = torManager.restart(
                null, // fail silently by omitting failure callback
                (TorCallback<Object>) restartSuccess -> {

                    Log.d(TAG, "Tor restarted successfully");

                    Task restartTask2 = torManager.restart(
                        // Use the provided instance that will automatically throw
                        // the exception, which will pipe it to the handler.
                        TorCallback.THROW,

                        new TorCallback<Object>() {
                            @Override
                            public void invoke(Object o) {
                                Log.d(TAG, "Tor restarted successfully");
                            }
                        }
                    );
                }
            );
        }
    );
}

kmp-tor's People

Contributors

05nelsonm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

kmp-tor's Issues

Add Process stream reader

Currently, Jvm and Android start Tor via a Process. Reading the inputStream and errorStream and routing to listeners via TorManagerEvent dispatching is needed in order to better facilitate debugging.

Will require refactoring TorManagerEvent hierarchy.

Polling repo in Maven Staging fails

Recent upgrade of GradleMavenPublish caused maven central username/password retrieval to require calling rootProject.ext.get("...").toString() instead of ext.get("...").toString(). This causes polling of staged binary library to fail authentication when enabled.

Controller throws exception on `25x` coded replies

Interactions with TorController result in an exception being thrown when Tor returns a non 250 coded ReplyLine. For example, 251, or 252.

25x codes are successes, but denote that something else happened. They should not return in a kotlin.Result.Failure.

JavaFx Windows fails to start Tor

Running the JavaFx sample on Windows results in an exception stating "Tor Stopped Early. Bad Config?", even though tests for kmp-tor module pass on Windows and Tor runs fine.

#25 is needed for further debugging.

Add ability to spin up multiple Tor instances

Currently, TorManager manages a single instance of Tor via use of static locks (Mutex's) with it's queue. Adding the ability to pass in a mutex via constructor argument would allow for declaring multiple Tor instances.

Java Library consumer could better load balance across multiple servers running separate instances. Would require different TorConfigProvider.workDir declarations.

Add Onion response parse failure

When adding an existing onion address via it's private key, parsing the controller response fails because the flag DiscardPK is not set and it is expecting a private key to be returned.

Controller should use the private key from the request in the returned HiddenServiceEntry

2022-04-05 07:15:17.721 5208-5208/io.toxicity.push I/System.out: D/TorListener: Action.Controller
2022-04-05 07:15:17.724 5208-5208/io.toxicity.push I/System.out: D/TorListener: >> ADD_ONION ED25519-V3:sGEW/Jjx6F0XrM4WZPsjUNUZrIRxb005HCxFcxN9o1T8ZLOGoLIYXkwAnvWZSIn2qE4s+UA7o9CKvQd8nKLKQA Port=443,127.0.0.1:61267
2022-04-05 07:15:17.826 5208-5208/io.toxicity.push I/System.out: D/TorListener: << 250-ServiceID=3bx4j5cueerin2bhif23vd3ibxol55px544ijgnfbgvj5nb5sytcbdqd
2022-04-05 07:15:17.826 5208-5208/io.toxicity.push I/System.out: D/TorListener: << 250 OK
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push I/System.out: E/TorListener: Failed to add HiddenService for ServerName(value=PushServer)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err: io.matthewnelson.kmp.tor.controller.common.exceptions.TorControllerException: Failed to parse reply for onion address private key
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at io.matthewnelson.kmp.tor.controller.RealTorControlProcessor$onionAdd$hsEntry$1.invoke(TorControlProcessor.kt:542)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at io.matthewnelson.kmp.tor.controller.RealTorControlProcessor$onionAdd$hsEntry$1.invoke(TorControlProcessor.kt:510)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at io.matthewnelson.kmp.tor.controller.RealTorController$RealControlPortInteractor$processCommand$2.invokeSuspend(TorController.kt:231)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:39)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
2022-04-05 07:15:17.879 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
2022-04-05 07:15:17.880 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
2022-04-05 07:15:17.880 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
2022-04-05 07:15:17.881 5208-5208/io.toxicity.push W/System.err:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

Add `TorManagerEvent` to proc 1 time startup operations

Add a TorManagerEvent that is dispatched to listeners in order to proc 1 time startup operations.

  • Should be dispatched after first populated AddressInfo is dispatched.
  • Should only be dispatched once per Tor start (not affected by DisableNetwork)

Revert issue #54

Client Authorization can only have a single private key added for a given hidden service address. Previous implementation was correct in returning a single entry instead of a list.

Issue #54 must be reverted

`TorService` stops on task removed when operating in background

Set default stop_service_on_task_removed to false when enable_foreground is false such that TorService.onDestroy will kill everything. This allows other Foreground Services that are inhibiting application process death from occuring to still have TorService running w/o it being killed prematurely.

Will also need to add isServiceDestroyed callback to notification as a fallback to the render method logic so we aren't creating a new notification if listener is not removed properly.

Add ability to retrieve `AddressInfo` value from `TorManager`

Currently, the only way to retrieve AddressInfo is by using a listener and storing whatever the latest dispatched value is.

  • Add to TorStateManager an addressInfo property
  • Add to AddressInfo an EMPTY value to be returned when queried when Tor has not yet completed bootstrapping.

Rework `Destroyable`

Currently, Destroyable.destroy always launches a coroutine in order to shutdown. This is inconvenient and needs:

  • Ability to shutdown immediately
  • A callback for when destruction is completed in order to invoke process exit if needed.

Foreground service exitProcess override

Add ability to override via application flag, the call to exitProcess for when the service is running in the Foreground and is destroyed when the task is removed.

[ TorConfig ] Add support for HashControlPassword

Add ability to set HashedContorlPassword in the TorConfig.

  • :library:manager:kmp-tor-manager.TorConfigProvider.retrieve method should implement logic to discern between which method to utilize when authenticating (cookie auth, or password).
  • :library:controller:kmp-tor-controller-common should have implementation to generate or consume a secret, providing the S2K computed string value.
  • :library:controller:kmp-tor-controller-common should have implementation of a wrapper class to denote valid S2K computed value to be set in the config.

See the Spec for more details.

[Suggestion] Sample Addition

Hey, I'm pretty new in the whole kotlin space so forgive me if this is redundant, but, as far as I'm aware javaFX isn't embedded in the JRE by default anymore, making it an additional dependency users have too install.

Saying that would it be possible for you too supply a sample that doesn't utilize javafx, maybe just a pure console application or something as this is what the application I'm working on is based around.

Awaiting your response, sorry for my bad English.

--Shiro

geoip6 file not being extracted

On GeoIP file update, files are not being extracted b/c they are split between 2 methods. when geoipv4 is extracted, the sha256sum file is written. Then when it comes time to extract the geoipv6 file, the new sha256sum file is written and geoipv6 file exists, so extraction is being skipped.

`TorController` fails to parse `TorEvent.ConfChanged`

ConfChanged is not a multi-line event (does not start with + character when read off the socket).

Tor dispatches the following:

250 OK
650-CONF_CHANGED
650-ConnectionPadding=0
650-DormantTimeoutDisabledByIdleStreams=0
650 OK

upon notifying of listeners, the event string is failing to be parsed because there is no message on the 650-CONF_CHANGED line to split. Instead, if splitting fails to occur, the message needs to be checked to see if it is ConfChanged, and then enter some sort of configChangedMode where by each following line is dispatched as an individual ConfChanged event.

This would also be a good time to add better error handling so that the exception thrown is more informative (contains the replies that caused the failure).

`Ports` cannot be expressed multiple times in `TorConfig`

Per the spec for:

Directives can be specified multiple times to bind to multiple address/ports.

the TorConfig.Setting.Ports sealed class should override equals/hashCode in order to also take into account their value when comparing in order to hold multiple Ports within a Set<TorConfig.Setting>.

Modification to the TorConfig.Builder methods will also need to be had such that remove -> removeInstanceOf

TorConfigProvider will also need to have it's validatePortOptions method modified to strip the client config of all port settings, validate them, and then add them to a new config after validation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.