
Packaging and distributing pre-compiled tor binaries and resources with exec/noexec and GPL/non‑GPL variants, reproducible builds, GPG-signed artifacts and checksum-verified releases.
This project is focused on the packaging and distribution of pre-compiled tor resources
for Kotlin Multiplatform, primarily to be consumed as a dependency for kmp-tor.
This is bisq-network/kmp-tor-resource, a fork of 05nelsonm/kmp-tor-resource that publishes tor security releases for the Bisq apps ahead of the upstream release cadence. Changes are kept upstreamable and offered back as pull requests.
io.github.rodvar.kmp-tor (same artifact ids
and package names as upstream). The two Gradle plugins are io.github.rodvar.kmp-tor.resource-frameworks
and io.github.rodvar.kmp-tor.resource-filterjar, because Maven Central only accepts plugin ids
under a namespace the publisher owns. The namespace is the publishing maintainer's, the same
trust model as the upstream io.matthewnelson coordinates; once a Bisq-owned namespace
(network.bisq) is verified the same tags are re-published there and consumers swap the group.SHA256SUMS list of every
published file.Bisq kmp-tor-resource signing <kmp-tor-resource@bisq.network>, fingerprint
4ECE E529 847B 49F1 81D6 9A7C 9BC4 7C3D 2AE1 FF8B. The public key is committed as
kmp-tor-resource-signing-key.asc and published on
keys.openpgp.org:
gpg --import kmp-tor-resource-signing-key.asc
# or: gpg --keyserver hkps://keys.openpgp.org --recv-keys 4ECEE529847B49F181D69A7C9BC47C3D2AE1FF8B
gpg --verify resource-exec-tor-gpl-409.14.0.pom.asc resource-exec-tor-gpl-409.14.0.pomexternal/codesign can only be regenerated by the upstream maintainer, so this fork gives the
Apple compilations (macOS, iOS Simulator) a deterministic ad-hoc signature at packaging
(--adhoc-codesign, via rcodesign) and leaves the Windows binaries unsigned. Ad-hoc signed
code loads on Apple Silicon and in the iOS Simulator, and runs locally on macOS, but is not
notarized: do not distribute the desktop binaries, use the upstream coordinates for that.build-logic.Consumer setup (Gradle Kotlin DSL). Releases resolve from mavenCentral():
repositories {
mavenCentral()
}
dependencies {
implementation("io.github.rodvar.kmp-tor:resource-exec-tor-gpl:409.14.0") // Android
implementation("io.github.rodvar.kmp-tor:resource-noexec-tor-gpl:409.14.0") // iOS
}Publishing is done by the Publish workflow. A release is: set
VERSION_NAME in gradle.properties to the release version, push the tag with the same name, and
once the workflow has validated the deployment, release it in the
Central Portal. A manual dispatch builds and
signs a branch without uploading; with maven_central set it rehearses the Central upload too: use
an -rcN version for that and drop the validated deployment in the portal instead of releasing it.
Tor and its dependencies are compiled from source using the following versions
| git tag | |
|---|---|
| libevent | release-2.1.12-stable |
| openssl | openssl-3.5.5 |
| tor | tor-0.4.9.14 |
| xz | v5.8.2 |
| zlib | v1.3.1 |
NOTE: All macOS and Windows compilations are code signed so they work out of the box.
More details about how things are compiled can be found HERE
| aarch64 | armv7a | ppc64le | riscv64 | x86 | x86_64 | |
|---|---|---|---|---|---|---|
| Windows | ✔ | ✔ | ||||
| macOS | ✔ | ✔ | ||||
| Linux (android) | ✔ | ✔ | ✔ | ✔ | ||
| Linux (libc) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| Linux (musl) | ✔ | ✔ | ✔ | |||
| FreeBSD |
2 types of resources are available; exec and noexec. This is to support platforms where process
execution is not allowed (e.g. iOS).
resource-exec-tor and its -gpl variant:
ResourceLoader.Tor.Exec
iOS
resource-noexec-tor and its -gpl variant:
ResourceLoader.Tor.NoExec
Node.js
Even though tremendous work has gone into making the noexec dependencies as safe as possible by
unloading tor after each invocation of tor_run_main, there is no safer way to run tor than in
its own process (as it was designed). The exec dependency should be utilized whenever possible.
2 variants of tor are compiled; 1 with the flag --enable-gpl, and 1 without it.
Publications with the -gpl suffix are indicative of the presence of the --enable-gpl compile
time flag.
Both variants are positionally identical with the same package names, classes, resource
names/locations, etc. The only difference between them are the compilations of tor being provided.
Only 1 variant can be had for a project, as a conflict will occur if both are present.
build.gradle.kts
// BAD
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:$vKmpTorResource")
}
// BAD
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor-gpl:$vKmpTorResource")
}
// GOOD! (non-gpl)
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor:$vKmpTorResource")
}
// GOOD! (gpl)
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor-gpl:$vKmpTorResource")
}This is to respect the GPL licensed code tor is utilizing such that projects who
have a GPL license are able to take advantage of the new functionality, and projects who do
not have a GPL license can still utilize tor without infringing on the license.
// build.gradle.kts
dependencies {
val vKmpTorResource = "409.5.0"
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor:$vKmpTorResource")
// Alternatively, if wanting tor compiled with `--enable-gpl` (GPL v3 licensed code)
// implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:$vKmpTorResource")
// implementation("io.matthewnelson.kmp-tor:resource-noexec-tor-gpl:$vKmpTorResource")
}Some additional configuration may be necessary for your Android application.
If utilizing the -exec Android dependency, tor compilations must be extracted to the
ApplicationInfo.nativeLibraryDir when the application is installed:
// build.gradle.kts
android {
packaging {
jniLibs.useLegacyPackaging = true
}
}// gradle.properties
android.bundle.enableUncompressedNativeLibs=falseIf running unit tests for Android (not device/emulator), add the following dependency which
will provide the desktop compilations and use them in lieu of the android compilations.
// build.gradle.kts
dependencies {
testImplementation("io.matthewnelson.kmp-tor:resource-android-unit-test-tor:$vKmpTorResource")
// Alternatively, if using the `-gpl` variants
// testImplementation("io.matthewnelson.kmp-tor:resource-android-unit-test-tor-gpl:$vKmpTorResource")
}Optionally, configure splits for each ABI:
// build.gradle.kts
android {
splits {
abi {
isEnable = true
reset()
include("x86", "armeabi-v7a", "arm64-v8a", "x86_64")
isUniversalApk = true
}
}
}Some additional configuration is necessary for your Android application. tor compilations are not
shipped with the resource-exec-tor{-gpl} or resource-noexec-tor{-gpl} Android Native dependencies,
they are packaged separately in an .aar and expected to be present at runtime.
If utilizing the resource-exec-tor{-gpl} Android Native dependency:
tor compilations to your Android application:
// build.gradle.kts
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-compilation-exec-tor:$vKmpTorResource")
// Alternatively, if using the `-gpl` variants
// implementation("io.matthewnelson.kmp-tor:resource-compilation-exec-tor-gpl:$vKmpTorResource")
}tor compilations must be extracted to the ApplicationInfo.nativeLibraryDir when the
application is installed:
// build.gradle.kts
android {
packaging {
jniLibs.useLegacyPackaging = true
}
}// gradle.properties
android.bundle.enableUncompressedNativeLibs=falseIf utilizing the resource-noexec-tor{-gpl} Android Native dependency:
libtor compilations to your Android application:
// build.gradle.kts
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-compilation-lib-tor:$vKmpTorResource")
// Alternatively, if using the `-gpl` variants
// implementation("io.matthewnelson.kmp-tor:resource-compilation-lib-tor-gpl:$vKmpTorResource")
}Optionally, configure splits for each ABI:
// build.gradle.kts
android {
splits {
abi {
isEnable = true
reset()
include("x86", "armeabi-v7a", "arm64-v8a", "x86_64")
isUniversalApk = true
}
}
}See the frameworks gradle plugin README for more details.
See the filterjar gradle plugin README for more details.
See the npmjs README for more details.
If utilizing with kmp-tor, simply pass into TorRuntime.Environment.Builder.
ResourceLoaderTorExec via resource-exec-tor dependency (or its -gpl variant)val env = TorRuntime.Environment.Builder(myWorkDir, myCacheDir, ResourceLoaderTorExec::getOrCreate)ResourceLoaderTorNoExec via resource-noexec-tor dependency (or its -gpl variant)val env = TorRuntime.Environment.Builder(myWorkDir, myCacheDir, ResourceLoaderTorNoExec::getOrCreate)See kmp-tor-samples for more details.
This project is focused on the packaging and distribution of pre-compiled tor resources
for Kotlin Multiplatform, primarily to be consumed as a dependency for kmp-tor.
This is bisq-network/kmp-tor-resource, a fork of 05nelsonm/kmp-tor-resource that publishes tor security releases for the Bisq apps ahead of the upstream release cadence. Changes are kept upstreamable and offered back as pull requests.
io.github.rodvar.kmp-tor (same artifact ids
and package names as upstream). The two Gradle plugins are io.github.rodvar.kmp-tor.resource-frameworks
and io.github.rodvar.kmp-tor.resource-filterjar, because Maven Central only accepts plugin ids
under a namespace the publisher owns. The namespace is the publishing maintainer's, the same
trust model as the upstream io.matthewnelson coordinates; once a Bisq-owned namespace
(network.bisq) is verified the same tags are re-published there and consumers swap the group.SHA256SUMS list of every
published file.Bisq kmp-tor-resource signing <kmp-tor-resource@bisq.network>, fingerprint
4ECE E529 847B 49F1 81D6 9A7C 9BC4 7C3D 2AE1 FF8B. The public key is committed as
kmp-tor-resource-signing-key.asc and published on
keys.openpgp.org:
gpg --import kmp-tor-resource-signing-key.asc
# or: gpg --keyserver hkps://keys.openpgp.org --recv-keys 4ECEE529847B49F181D69A7C9BC47C3D2AE1FF8B
gpg --verify resource-exec-tor-gpl-409.14.0.pom.asc resource-exec-tor-gpl-409.14.0.pomexternal/codesign can only be regenerated by the upstream maintainer, so this fork gives the
Apple compilations (macOS, iOS Simulator) a deterministic ad-hoc signature at packaging
(--adhoc-codesign, via rcodesign) and leaves the Windows binaries unsigned. Ad-hoc signed
code loads on Apple Silicon and in the iOS Simulator, and runs locally on macOS, but is not
notarized: do not distribute the desktop binaries, use the upstream coordinates for that.build-logic.Consumer setup (Gradle Kotlin DSL). Releases resolve from mavenCentral():
repositories {
mavenCentral()
}
dependencies {
implementation("io.github.rodvar.kmp-tor:resource-exec-tor-gpl:409.14.0") // Android
implementation("io.github.rodvar.kmp-tor:resource-noexec-tor-gpl:409.14.0") // iOS
}Publishing is done by the Publish workflow. A release is: set
VERSION_NAME in gradle.properties to the release version, push the tag with the same name, and
once the workflow has validated the deployment, release it in the
Central Portal. A manual dispatch builds and
signs a branch without uploading; with maven_central set it rehearses the Central upload too: use
an -rcN version for that and drop the validated deployment in the portal instead of releasing it.
Tor and its dependencies are compiled from source using the following versions
| git tag | |
|---|---|
| libevent | release-2.1.12-stable |
| openssl | openssl-3.5.5 |
| tor | tor-0.4.9.14 |
| xz | v5.8.2 |
| zlib | v1.3.1 |
NOTE: All macOS and Windows compilations are code signed so they work out of the box.
More details about how things are compiled can be found HERE
| aarch64 | armv7a | ppc64le | riscv64 | x86 | x86_64 | |
|---|---|---|---|---|---|---|
| Windows | ✔ | ✔ | ||||
| macOS | ✔ | ✔ | ||||
| Linux (android) | ✔ | ✔ | ✔ | ✔ | ||
| Linux (libc) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| Linux (musl) | ✔ | ✔ | ✔ | |||
| FreeBSD |
2 types of resources are available; exec and noexec. This is to support platforms where process
execution is not allowed (e.g. iOS).
resource-exec-tor and its -gpl variant:
ResourceLoader.Tor.Exec
iOS
resource-noexec-tor and its -gpl variant:
ResourceLoader.Tor.NoExec
Node.js
Even though tremendous work has gone into making the noexec dependencies as safe as possible by
unloading tor after each invocation of tor_run_main, there is no safer way to run tor than in
its own process (as it was designed). The exec dependency should be utilized whenever possible.
2 variants of tor are compiled; 1 with the flag --enable-gpl, and 1 without it.
Publications with the -gpl suffix are indicative of the presence of the --enable-gpl compile
time flag.
Both variants are positionally identical with the same package names, classes, resource
names/locations, etc. The only difference between them are the compilations of tor being provided.
Only 1 variant can be had for a project, as a conflict will occur if both are present.
build.gradle.kts
// BAD
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:$vKmpTorResource")
}
// BAD
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor-gpl:$vKmpTorResource")
}
// GOOD! (non-gpl)
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor:$vKmpTorResource")
}
// GOOD! (gpl)
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor-gpl:$vKmpTorResource")
}This is to respect the GPL licensed code tor is utilizing such that projects who
have a GPL license are able to take advantage of the new functionality, and projects who do
not have a GPL license can still utilize tor without infringing on the license.
// build.gradle.kts
dependencies {
val vKmpTorResource = "409.5.0"
implementation("io.matthewnelson.kmp-tor:resource-exec-tor:$vKmpTorResource")
implementation("io.matthewnelson.kmp-tor:resource-noexec-tor:$vKmpTorResource")
// Alternatively, if wanting tor compiled with `--enable-gpl` (GPL v3 licensed code)
// implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:$vKmpTorResource")
// implementation("io.matthewnelson.kmp-tor:resource-noexec-tor-gpl:$vKmpTorResource")
}Some additional configuration may be necessary for your Android application.
If utilizing the -exec Android dependency, tor compilations must be extracted to the
ApplicationInfo.nativeLibraryDir when the application is installed:
// build.gradle.kts
android {
packaging {
jniLibs.useLegacyPackaging = true
}
}// gradle.properties
android.bundle.enableUncompressedNativeLibs=falseIf running unit tests for Android (not device/emulator), add the following dependency which
will provide the desktop compilations and use them in lieu of the android compilations.
// build.gradle.kts
dependencies {
testImplementation("io.matthewnelson.kmp-tor:resource-android-unit-test-tor:$vKmpTorResource")
// Alternatively, if using the `-gpl` variants
// testImplementation("io.matthewnelson.kmp-tor:resource-android-unit-test-tor-gpl:$vKmpTorResource")
}Optionally, configure splits for each ABI:
// build.gradle.kts
android {
splits {
abi {
isEnable = true
reset()
include("x86", "armeabi-v7a", "arm64-v8a", "x86_64")
isUniversalApk = true
}
}
}Some additional configuration is necessary for your Android application. tor compilations are not
shipped with the resource-exec-tor{-gpl} or resource-noexec-tor{-gpl} Android Native dependencies,
they are packaged separately in an .aar and expected to be present at runtime.
If utilizing the resource-exec-tor{-gpl} Android Native dependency:
tor compilations to your Android application:
// build.gradle.kts
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-compilation-exec-tor:$vKmpTorResource")
// Alternatively, if using the `-gpl` variants
// implementation("io.matthewnelson.kmp-tor:resource-compilation-exec-tor-gpl:$vKmpTorResource")
}tor compilations must be extracted to the ApplicationInfo.nativeLibraryDir when the
application is installed:
// build.gradle.kts
android {
packaging {
jniLibs.useLegacyPackaging = true
}
}// gradle.properties
android.bundle.enableUncompressedNativeLibs=falseIf utilizing the resource-noexec-tor{-gpl} Android Native dependency:
libtor compilations to your Android application:
// build.gradle.kts
dependencies {
implementation("io.matthewnelson.kmp-tor:resource-compilation-lib-tor:$vKmpTorResource")
// Alternatively, if using the `-gpl` variants
// implementation("io.matthewnelson.kmp-tor:resource-compilation-lib-tor-gpl:$vKmpTorResource")
}Optionally, configure splits for each ABI:
// build.gradle.kts
android {
splits {
abi {
isEnable = true
reset()
include("x86", "armeabi-v7a", "arm64-v8a", "x86_64")
isUniversalApk = true
}
}
}See the frameworks gradle plugin README for more details.
See the filterjar gradle plugin README for more details.
See the npmjs README for more details.
If utilizing with kmp-tor, simply pass into TorRuntime.Environment.Builder.
ResourceLoaderTorExec via resource-exec-tor dependency (or its -gpl variant)val env = TorRuntime.Environment.Builder(myWorkDir, myCacheDir, ResourceLoaderTorExec::getOrCreate)ResourceLoaderTorNoExec via resource-noexec-tor dependency (or its -gpl variant)val env = TorRuntime.Environment.Builder(myWorkDir, myCacheDir, ResourceLoaderTorNoExec::getOrCreate)See kmp-tor-samples for more details.