diff --git a/build.gradle b/build.gradle index 46b97f8065e818812d78e5c1720bb3633360e86a..08d2c86301ccb8bb1c695f7eadf81e988dc16344 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' - ext.hilt_version = '2.40' - ext.nav_version = '2.4.2' - ext.tor_version = '0.4.5.12-2' - ext.obfs4_version = '0.0.12' - ext.junit_version = '5.7.2' - ext.mockk_version = '1.10.4' - ext.ktlint_plugin_version = '10.2.1' + apply from: "gradle/variables.gradle" repositories { google() diff --git a/gradle/variables.gradle b/gradle/variables.gradle new file mode 100644 index 0000000000000000000000000000000000000000..93ffcbcb9dc31042435d8efeccf4ab60f01be706 --- /dev/null +++ b/gradle/variables.gradle @@ -0,0 +1,10 @@ +ext { + kotlin_version = '1.7.10' + hilt_version = '2.43.2' + nav_version = '2.4.2' + tor_version = '0.4.5.12-2' + obfs4_version = '0.0.12' + junit_version = '5.7.2' + mockk_version = '1.10.4' + ktlint_plugin_version = '10.2.1' +} diff --git a/mailbox-android/build.gradle b/mailbox-android/build.gradle index b90aa3a89cb46cda4626a0c5b983c59faad7454a..7f0aa388a6f3740cf3e7d5e9776157375dcac03b 100644 --- a/mailbox-android/build.gradle +++ b/mailbox-android/build.gradle @@ -10,6 +10,10 @@ plugins { id 'checkstyle' // only needed for Java code } +checkstyle { + configFile = new File('../config/checkstyle/checkstyle.xml') +} + android { compileSdkVersion 32 buildToolsVersion "32.0.0" @@ -148,5 +152,5 @@ tasks.withType(MergeResources) { dependsOn unpackTorBinaries } -apply from: "${rootProject.rootDir}/gradle/ktlint.gradle" -apply from: "${rootProject.rootDir}/gradle/checkstyle.gradle" +apply from: "../gradle/ktlint.gradle" +apply from: "../gradle/checkstyle.gradle" diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt index 918541561ffd28db6cb217b45024757e2e3dbd19..02ce9bc366c3deab30161e44d7e5fcce4a2e239b 100644 --- a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt @@ -32,8 +32,10 @@ import org.briarproject.mailbox.core.db.DatabaseConfig import org.briarproject.mailbox.core.files.FileProvider import org.briarproject.mailbox.core.lifecycle.LifecycleManager import org.briarproject.mailbox.core.system.DozeWatchdog +import org.briarproject.mailbox.core.system.System import java.io.File import javax.inject.Singleton +import kotlin.system.exitProcess @Module( includes = [ @@ -73,4 +75,8 @@ internal class AppModule { @Singleton @Provides fun provideDozeHelper(): DozeHelper = DozeHelperImpl() + + @Singleton + @Provides + fun provideSystem() = System { code -> exitProcess(code) } } diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxService.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxService.kt index e03afbf92355bf008dca8be3141fa1291101f98e..9063966276531a1f217a494dbeb3bd881128b8f9 100644 --- a/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxService.kt +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/MailboxService.kt @@ -42,11 +42,11 @@ import org.briarproject.mailbox.core.lifecycle.LifecycleManager.StartResult.SUCC import org.briarproject.mailbox.core.system.AndroidExecutor import org.briarproject.mailbox.core.system.AndroidWakeLock import org.briarproject.mailbox.core.system.AndroidWakeLockManager +import org.briarproject.mailbox.core.system.System import org.briarproject.mailbox.core.util.LogUtils.warn import org.slf4j.LoggerFactory.getLogger import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject -import kotlin.system.exitProcess @AndroidEntryPoint class MailboxService : Service() { @@ -83,6 +83,9 @@ class MailboxService : Service() { @Inject internal lateinit var androidExecutor: AndroidExecutor + @Inject + internal lateinit var system: System + private lateinit var lifecycleWakeLock: AndroidWakeLock override fun onCreate() { @@ -179,7 +182,7 @@ class MailboxService : Service() { } stopSelf() LOG.info("Exiting") - exitProcess(1) + system.exit(1) } } } diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/WipeCompleteFragment.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/WipeCompleteFragment.kt index dcd9c7aafe81a2ed6ce77ed52f0df215aa57eb95..874cddc3108f73d7578e3359e744fa3cbf22ac8f 100644 --- a/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/WipeCompleteFragment.kt +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/ui/WipeCompleteFragment.kt @@ -27,8 +27,9 @@ import android.widget.Button import androidx.fragment.app.Fragment import dagger.hilt.android.AndroidEntryPoint import org.briarproject.mailbox.R +import org.briarproject.mailbox.core.system.System import org.slf4j.LoggerFactory.getLogger -import kotlin.system.exitProcess +import javax.inject.Inject @AndroidEntryPoint class WipeCompleteFragment : Fragment() { @@ -37,6 +38,9 @@ class WipeCompleteFragment : Fragment() { private val LOG = getLogger(WipeCompleteFragment::class.java) } + @Inject + internal lateinit var system: System + private lateinit var button: Button override fun onCreateView( @@ -52,7 +56,7 @@ class WipeCompleteFragment : Fragment() { button.setOnClickListener { LOG.info("Exiting") - exitProcess(0) + system.exit(0) } } diff --git a/mailbox-cli/build.gradle b/mailbox-cli/build.gradle index af3ca3157a02eb65c1757126bb02d0a1e62a9860..531841c63d53dd9ead0f5bf18cf562cf8c934bb7 100644 --- a/mailbox-cli/build.gradle +++ b/mailbox-cli/build.gradle @@ -10,29 +10,18 @@ plugins { id 'org.jetbrains.kotlin.jvm' id 'org.jetbrains.kotlin.kapt' id "org.jlleitschuh.gradle.ktlint" version "$ktlint_plugin_version" - id 'checkstyle' } sourceCompatibility = 1.8 targetCompatibility = 1.8 -configurations { - tor -} - dependencies { implementation project(path: ':mailbox-core', configuration: 'default') + implementation project(path: ':mailbox-lib', configuration: 'default') implementation "ch.qos.logback:logback-classic:1.2.10" implementation 'com.github.ajalt:clikt:2.2.0' - def jna_version = '5.8.0' - implementation "net.java.dev.jna:jna:$jna_version" - implementation "net.java.dev.jna:jna-platform:$jna_version" - tor "org.briarproject:tor-linux:$tor_version" - tor "org.briarproject:obfs4proxy-linux:$obfs4_version" - - implementation "com.google.dagger:hilt-core:$hilt_version" kapt "com.google.dagger:hilt-compiler:$hilt_version" testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version" @@ -52,7 +41,7 @@ test { } } -apply from: "${rootProject.rootDir}/gradle/ktlint.gradle" +apply from: "../gradle/ktlint.gradle" // At the moment for non-Android projects we need to explicitly mark the code generated by kapt // as 'generated source code' for correct highlighting and resolve in IDE. @@ -64,31 +53,6 @@ idea { } } -def torBinariesDir = 'src/main/resources' - -task cleanTorBinaries { - doLast { - delete fileTree(torBinariesDir) { include '*.zip' } - } -} - -clean.dependsOn cleanTorBinaries - -task unpackTorBinaries { - doLast { - copy { - from configurations.tor.collect { zipTree(it) } - into torBinariesDir - } - } - dependsOn cleanTorBinaries -} - -processResources { - inputs.dir torBinariesDir - dependsOn unpackTorBinaries -} - void jarFactory(Jar jarTask, jarArchitecture) { jarTask.doFirst { println 'Building ' + jarArchitecture + ' version has started' diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt b/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt index a2292d4b0b66303b48957d712b91430fcd6e7009..da436f36811783ebe5a1f13d05d44fd73a554bfb 100644 --- a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt +++ b/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt @@ -25,21 +25,9 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.options.counted import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option -import kotlinx.coroutines.flow.takeWhile -import kotlinx.coroutines.runBlocking -import org.briarproject.mailbox.core.CoreEagerSingletons -import org.briarproject.mailbox.core.JavaCliEagerSingletons -import org.briarproject.mailbox.core.db.TransactionManager -import org.briarproject.mailbox.core.lifecycle.LifecycleManager -import org.briarproject.mailbox.core.setup.QrCodeEncoder -import org.briarproject.mailbox.core.setup.SetupManager -import org.briarproject.mailbox.core.setup.WipeManager import org.briarproject.mailbox.core.system.InvalidIdException -import org.briarproject.mailbox.core.tor.TorPlugin -import org.briarproject.mailbox.core.tor.TorState +import org.briarproject.mailbox.lib.Mailbox import org.slf4j.LoggerFactory.getLogger -import javax.inject.Inject -import kotlin.system.exitProcess class Main : CliktCommand( name = "briar-mailbox", @@ -62,30 +50,6 @@ class Main : CliktCommand( ).counted() private val setupToken: String? by option("--setup-token", hidden = true) - @Inject - internal lateinit var coreEagerSingletons: CoreEagerSingletons - - @Inject - internal lateinit var javaCliEagerSingletons: JavaCliEagerSingletons - - @Inject - internal lateinit var lifecycleManager: LifecycleManager - - @Inject - internal lateinit var db: TransactionManager - - @Inject - internal lateinit var setupManager: SetupManager - - @Inject - internal lateinit var wipeManager: WipeManager - - @Inject - internal lateinit var torPlugin: TorPlugin - - @Inject - internal lateinit var qrCodeEncoder: QrCodeEncoder - override fun run() { // logging val levelNamed = when { @@ -107,56 +71,46 @@ class Main : CliktCommand( getLogger(this.javaClass).debug("Hello Mailbox") println("Hello Mailbox") - val javaCliComponent = DaggerJavaCliComponent.builder().build() - javaCliComponent.inject(this) + val mailbox = Mailbox() if (wipe) { - wipeManager.wipeFilesOnly() + mailbox.wipeFilesOnly() println("Mailbox wiped successfully \\o/") - exitProcess(0) + mailbox.getSystem().exit(0) } - startLifecycle() + startLifecycle(mailbox) } - private fun startLifecycle() { + private fun startLifecycle(mailbox: Mailbox) { Runtime.getRuntime().addShutdownHook( Thread { - lifecycleManager.stopServices(false) - lifecycleManager.waitForShutdown() + mailbox.stopLifecycle(false) + mailbox.waitForShutdown() } ) - lifecycleManager.startServices() - lifecycleManager.waitForStartup() + mailbox.startLifecycle() if (setupToken != null) { try { - setupManager.setToken(setupToken, null) + mailbox.setSetupToken(setupToken!!) } catch (e: InvalidIdException) { System.err.println("Invalid setup token") - exitProcess(1) + mailbox.getSystem().exit(1) } } - val ownerTokenExists = db.read { txn -> - setupManager.getOwnerToken(txn) != null - } + val ownerTokenExists = mailbox.getOwnerToken() != null if (!ownerTokenExists) { if (debug) { - val token = setupToken ?: db.read { setupManager.getSetupToken(it) } + val token = setupToken ?: mailbox.getSetupToken() println( "curl -v -H \"Authorization: Bearer $token\" -X PUT " + "http://localhost:8000/setup" ) } - // If not set up, show QR code for manual setup - runBlocking { - // wait until Tor becomes active and published the onion service - torPlugin.state.takeWhile { state -> - state != TorState.Published - }.collect { } - } - qrCodeEncoder.getQrCodeBitMatrix()?.let { + mailbox.waitForTorPublished() + mailbox.getQrCode()?.let { println(QrCodeRenderer.getQrString(it)) } } diff --git a/mailbox-core/build.gradle b/mailbox-core/build.gradle index f26a8013c7b01af2bbcc7e039b63c23f1b9a4d7d..4395acef1da32b74275837c741a5ad04e94a9a01 100644 --- a/mailbox-core/build.gradle +++ b/mailbox-core/build.gradle @@ -7,6 +7,10 @@ plugins { id 'checkstyle' } +checkstyle { + configFile = new File('../config/checkstyle/checkstyle.xml') +} + sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -67,4 +71,4 @@ idea { } } -apply from: "${rootProject.rootDir}/gradle/ktlint.gradle" +apply from: "../gradle/ktlint.gradle" diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt index 1a76a857ec0ac89251afd7ea148309f8f52c569c..a668fa64ad7579d762c072bc0281a1e934bda9ae 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManagerImpl.kt @@ -37,6 +37,7 @@ import org.briarproject.mailbox.core.lifecycle.LifecycleManager.StartResult.LIFE import org.briarproject.mailbox.core.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR import org.briarproject.mailbox.core.lifecycle.LifecycleManager.StartResult.SUCCESS import org.briarproject.mailbox.core.setup.WipeManager +import org.briarproject.mailbox.core.system.System import org.briarproject.mailbox.core.util.LogUtils.info import org.briarproject.mailbox.core.util.LogUtils.logDuration import org.briarproject.mailbox.core.util.LogUtils.logException @@ -52,12 +53,12 @@ import javax.annotation.concurrent.GuardedBy import javax.annotation.concurrent.ThreadSafe import javax.inject.Inject import kotlin.concurrent.thread -import kotlin.system.exitProcess @ThreadSafe internal class LifecycleManagerImpl @Inject constructor( private val db: Database, private val wipeManager: WipeManager, + private val system: System, ) : LifecycleManager, MigrationListener { @@ -219,7 +220,7 @@ internal class LifecycleManagerImpl @Inject constructor( // deadlock by itself. if (stopped && exitAfterStopping) { LOG.info("Exiting") - exitProcess(0) + system.exit(0) } } } diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/System.java b/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/System.java new file mode 100644 index 0000000000000000000000000000000000000000..527e6d0667d47b069143e6ec2746d7294131cab7 --- /dev/null +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/system/System.java @@ -0,0 +1,24 @@ +/* + * Briar Mailbox + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package org.briarproject.mailbox.core.system; + +public interface System { + void exit(int code); +} diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt index a9d9d98a97103d6b2e00a2c4b7f3fc8de946fa18..0aaf46a163f8be9b637b074dc7f2ecd4da084576 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt @@ -14,6 +14,7 @@ import org.briarproject.mailbox.core.server.WebServerModule import org.briarproject.mailbox.core.settings.SettingsModule import org.briarproject.mailbox.core.setup.SetupModule import org.briarproject.mailbox.core.system.Clock +import org.briarproject.mailbox.core.system.System import org.briarproject.mailbox.core.system.TestTaskSchedulerModule import java.io.File import java.util.concurrent.Executor @@ -35,7 +36,11 @@ import javax.inject.Singleton internal class TestModule(private val tempDir: File) { @Singleton @Provides - fun provideClock() = Clock { System.currentTimeMillis() } + fun provideClock() = Clock { java.lang.System.currentTimeMillis() } + + @Singleton + @Provides + fun provideSystem() = System { /* do nothing on exit */ } @Singleton @Provides diff --git a/mailbox-cli/.gitignore b/mailbox-lib/.gitignore similarity index 100% rename from mailbox-cli/.gitignore rename to mailbox-lib/.gitignore diff --git a/mailbox-lib/build.gradle b/mailbox-lib/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..3e200c658032afad89975ebec3cc155316cfb90b --- /dev/null +++ b/mailbox-lib/build.gradle @@ -0,0 +1,86 @@ +plugins { + id 'java-library' + id 'idea' + id 'org.jetbrains.kotlin.jvm' + id 'org.jetbrains.kotlin.kapt' + id "org.jlleitschuh.gradle.ktlint" version "$ktlint_plugin_version" + id 'checkstyle' +} + +checkstyle { + configFile = new File('../config/checkstyle/checkstyle.xml') +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +configurations { + tor +} + +dependencies { + implementation project(path: ':mailbox-core', configuration: 'default') + + def jna_version = '5.8.0' + implementation "net.java.dev.jna:jna:$jna_version" + implementation "net.java.dev.jna:jna-platform:$jna_version" + tor "org.briarproject:tor-linux:$tor_version" + tor "org.briarproject:obfs4proxy-linux:$obfs4_version" + + implementation "com.google.dagger:hilt-core:$hilt_version" + kapt "com.google.dagger:hilt-compiler:$hilt_version" + + testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version" + testImplementation "org.junit.jupiter:junit-jupiter-params:$junit_version" + testImplementation "org.junit.jupiter:junit-jupiter-engine:$junit_version" + testImplementation "io.mockk:mockk:$mockk_version" + testImplementation "ch.qos.logback:logback-classic:1.2.10" +} + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} + +apply from: "../gradle/ktlint.gradle" + +// At the moment for non-Android projects we need to explicitly mark the code generated by kapt +// as 'generated source code' for correct highlighting and resolve in IDE. +idea { + module { + sourceDirs += file('build/generated/source/kapt/main') + testSourceDirs += file('build/generated/source/kapt/test') + generatedSourceDirs += file('build/generated/source/kapt/main') + } +} + +def torBinariesDir = 'src/main/resources' + +task cleanTorBinaries { + doLast { + delete fileTree(torBinariesDir) { include '*.zip' } + } +} + +clean.dependsOn cleanTorBinaries + +task unpackTorBinaries { + doLast { + copy { + from configurations.tor.collect { zipTree(it) } + into torBinariesDir + } + } + dependsOn cleanTorBinaries +} + +processResources { + inputs.dir torBinariesDir + dependsOn unpackTorBinaries +} + +tasks.withType(Test) { + systemProperty 'java.library.path', 'libs' +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/core/MailboxLibEagerSingletons.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/MailboxLibEagerSingletons.kt new file mode 100644 index 0000000000000000000000000000000000000000..079af827749d824257f9f92d98a6b58843f57e8c --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/MailboxLibEagerSingletons.kt @@ -0,0 +1,30 @@ +/* + * Briar Mailbox + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package org.briarproject.mailbox.core + +import org.briarproject.mailbox.core.system.TaskScheduler +import org.briarproject.mailbox.core.tor.TorPlugin +import javax.inject.Inject + +@Suppress("unused") +internal class MailboxLibEagerSingletons @Inject constructor( + val taskScheduler: TaskScheduler, + val javaTorPlugin: TorPlugin, +) diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt similarity index 96% rename from mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt rename to mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt index c2fec04fd94e3c8aaec06292d8dc2f49ecb2838c..904f84f13efc5ea4849783c2db2233ebd80ed8a1 100644 --- a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt @@ -41,7 +41,7 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -internal class JavaTorModule { +class JavaTorModule { companion object { private val LOG: Logger = getLogger(JavaTorModule::class.java) @@ -109,7 +109,7 @@ internal class JavaTorModule { @Provides @Singleton - fun provideNetworkManager(networkManager: JavaCliNetworkManager): NetworkManager { + fun provideNetworkManager(networkManager: MailboxLibNetworkManager): NetworkManager { return networkManager } diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java similarity index 100% rename from mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java rename to mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaCliNetworkManager.java b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/MailboxLibNetworkManager.java similarity index 91% rename from mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaCliNetworkManager.java rename to mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/MailboxLibNetworkManager.java index bb32ed6ccbeb5975d23bfbf29d72a01048c820cb..d7484cb13f8aab4a3d334d4b5930496da3f7b9c2 100644 --- a/mailbox-cli/src/main/java/org/briarproject/mailbox/core/tor/JavaCliNetworkManager.java +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/MailboxLibNetworkManager.java @@ -33,12 +33,12 @@ import static org.briarproject.mailbox.core.util.LogUtils.logException; import static org.briarproject.mailbox.core.util.NetworkUtils.getNetworkInterfaces; import static org.slf4j.LoggerFactory.getLogger; -class JavaCliNetworkManager implements NetworkManager { +public class MailboxLibNetworkManager implements NetworkManager { - private static final Logger LOG = getLogger(JavaCliNetworkManager.class); + private static final Logger LOG = getLogger(MailboxLibNetworkManager.class); @Inject - JavaCliNetworkManager() { + MailboxLibNetworkManager() { } @Override diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/AbstractMailbox.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/AbstractMailbox.kt new file mode 100644 index 0000000000000000000000000000000000000000..c07974ee1378df1ca6c30b1e0d4196edb94c5bc7 --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/AbstractMailbox.kt @@ -0,0 +1,135 @@ +/* + * Briar Mailbox + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package org.briarproject.mailbox.lib + +import com.google.zxing.common.BitMatrix +import kotlinx.coroutines.flow.takeWhile +import kotlinx.coroutines.runBlocking +import org.briarproject.mailbox.core.CoreEagerSingletons +import org.briarproject.mailbox.core.MailboxLibEagerSingletons +import org.briarproject.mailbox.core.db.TransactionManager +import org.briarproject.mailbox.core.lifecycle.LifecycleManager +import org.briarproject.mailbox.core.setup.QrCodeEncoder +import org.briarproject.mailbox.core.setup.SetupManager +import org.briarproject.mailbox.core.setup.WipeManager +import org.briarproject.mailbox.core.system.System +import org.briarproject.mailbox.core.tor.TorPlugin +import org.briarproject.mailbox.core.tor.TorState +import org.briarproject.mailbox.core.util.LogUtils.info +import org.slf4j.Logger +import org.slf4j.LoggerFactory.getLogger +import java.io.File +import javax.inject.Inject + +abstract class AbstractMailbox(protected val customDataDir: File? = null) { + + companion object { + val LOG: Logger = getLogger(AbstractMailbox::class.java) + } + + @Inject + internal lateinit var coreEagerSingletons: CoreEagerSingletons + + @Inject + internal lateinit var mailboxLibEagerSingletons: MailboxLibEagerSingletons + + @Inject + internal lateinit var lifecycleManager: LifecycleManager + + @Inject + internal lateinit var db: TransactionManager + + @Inject + internal lateinit var setupManager: SetupManager + + @Inject + internal lateinit var wipeManager: WipeManager + + @Inject + internal lateinit var torPlugin: TorPlugin + + @Inject + internal lateinit var qrCodeEncoder: QrCodeEncoder + + @Inject + internal lateinit var system: System + + fun wipeFilesOnly() { + wipeManager.wipeFilesOnly() + LOG.info { "Mailbox wiped successfully \\o/" } + } + + fun startLifecycle() { + LOG.info { "Starting lifecycle" } + lifecycleManager.startServices() + LOG.info { "Waiting for startup" } + lifecycleManager.waitForStartup() + LOG.info { "Startup finished" } + } + + fun stopLifecycle(exitAfterStopping: Boolean) { + LOG.info { "Stopping lifecycle" } + lifecycleManager.stopServices(exitAfterStopping) + LOG.info { "Waiting for shutdown" } + lifecycleManager.waitForShutdown() + LOG.info { "Shutdown finished" } + } + + fun setSetupToken(token: String) { + setupManager.setToken(token, null) + } + + fun setOwnerToken(token: String) { + setupManager.setToken(null, token) + } + + fun waitForTorPublished() { + LOG.info { "Waiting for Tor to publish hidden service" } + runBlocking { + // wait until Tor becomes active and published the onion service + torPlugin.state.takeWhile { state -> + state != TorState.Published + }.collect { } + } + LOG.info { "Hidden service published" } + } + + fun waitForShutdown() { + lifecycleManager.waitForShutdown() + } + + fun getSetupToken(): String? { + return db.read { txn -> + setupManager.getSetupToken(txn) + } + } + + fun getOwnerToken(): String? { + return db.read { txn -> + setupManager.getOwnerToken(txn) + } + } + + fun getQrCode(): BitMatrix? { + return qrCodeEncoder.getQrCodeBitMatrix() + } + + fun getSystem(): System = system +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/Mailbox.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/Mailbox.kt new file mode 100644 index 0000000000000000000000000000000000000000..115bb0717779cf5e3447358d70f9587b68b100ed --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/Mailbox.kt @@ -0,0 +1,14 @@ +package org.briarproject.mailbox.lib + +import org.briarproject.mailbox.core.util.LogUtils.info +import java.io.File + +class Mailbox(mailboxDir: File? = null) : AbstractMailbox(mailboxDir) { + + init { + LOG.info { "Hello Mailbox" } + val mailboxLibComponent = DaggerMailboxLibComponent.builder() + .mailboxLibModule(MailboxLibModule(customDataDir)).build() + mailboxLibComponent.inject(this) + } +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibComponent.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibComponent.kt new file mode 100644 index 0000000000000000000000000000000000000000..03ef11d02906328a201284370f86bea3c6988321 --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibComponent.kt @@ -0,0 +1,35 @@ +/* + * Briar Mailbox + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package org.briarproject.mailbox.lib + +import dagger.Component +import org.briarproject.mailbox.system.ProductionSystemModule +import javax.inject.Singleton + +@Singleton +@Component( + modules = [ + MailboxLibModule::class, + ProductionSystemModule::class, + ] +) +interface MailboxLibComponent { + fun inject(mailbox: Mailbox) +} diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibModule.kt similarity index 84% rename from mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt rename to mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibModule.kt index 1e90dcadd2f9929bea369ae47a054aeb263a2685..7b8a068cb9fc90f0f3440e321471b3c6ab52a20a 100644 --- a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibModule.kt @@ -17,7 +17,7 @@ * */ -package org.briarproject.mailbox.cli +package org.briarproject.mailbox.lib import dagger.Module import dagger.Provides @@ -51,10 +51,10 @@ import javax.inject.Singleton ] ) @InstallIn(SingletonComponent::class) -internal class JavaCliModule { +open class MailboxLibModule(private val customDataDir: File? = null) { companion object { - private val LOG: Logger = getLogger(JavaCliModule::class.java) + private val LOG: Logger = getLogger(MailboxLibModule::class.java) private val DEFAULT_DATAHOME = System.getProperty("user.home") + separator + ".local" + separator + "share" @@ -67,15 +67,19 @@ internal class JavaCliModule { * and otherwise it returns "~/.local/share/briar-mailbox". */ private val dataDir: File by lazy { - val dataHome = when (val custom = System.getenv("XDG_DATA_HOME").orEmpty()) { - "" -> File(DEFAULT_DATAHOME) - else -> File(custom) - } - if (!dataHome.exists() || !dataHome.isDirectory) { - throw IOException("datahome missing or not a directory: ${dataHome.absolutePath}") + val dataDir = if (customDataDir != null) { + customDataDir + } else { + val dataHome = when (val custom = System.getenv("XDG_DATA_HOME").orEmpty()) { + "" -> File(DEFAULT_DATAHOME) + else -> File(custom) + } + if (!dataHome.exists() || !dataHome.isDirectory) { + throw IOException("datahome missing or not a directory: ${dataHome.absolutePath}") + } + File(dataHome.absolutePath + separator + DATAHOME_SUBDIR) } - val dataDir = File(dataHome.absolutePath + separator + DATAHOME_SUBDIR) if (!dataDir.exists() && !dataDir.mkdirs()) { throw IOException("datadir could not be created: ${dataDir.absolutePath}") } else if (!dataDir.isDirectory) { diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliComponent.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibTestComponent.kt similarity index 79% rename from mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliComponent.kt rename to mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibTestComponent.kt index 34a4cb42feaa370f761dcc85c892e29bf251afd6..98bbba5297d4da5533b50b20a17231c9dbba7562 100644 --- a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliComponent.kt +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/MailboxLibTestComponent.kt @@ -17,17 +17,19 @@ * */ -package org.briarproject.mailbox.cli +package org.briarproject.mailbox.lib import dagger.Component +import org.briarproject.mailbox.system.TestSystemModule import javax.inject.Singleton @Singleton @Component( modules = [ - JavaCliModule::class, + MailboxLibModule::class, + TestSystemModule::class, ] ) -interface JavaCliComponent { - fun inject(main: Main) +interface MailboxLibTestComponent { + fun inject(mailbox: TestMailbox) } diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/TestMailbox.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/TestMailbox.kt new file mode 100644 index 0000000000000000000000000000000000000000..3d1b0784c30237bb57efb24d3d6b06b80fa5f563 --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/lib/TestMailbox.kt @@ -0,0 +1,27 @@ +package org.briarproject.mailbox.lib + +import org.briarproject.mailbox.core.util.LogUtils.info +import org.briarproject.mailbox.system.TestSystem +import java.io.File +import javax.inject.Inject + +class TestMailbox(mailboxDir: File? = null) : AbstractMailbox(mailboxDir) { + + init { + LOG.info { "Hello Mailbox" } + val mailboxLibComponent = DaggerMailboxLibTestComponent.builder() + .mailboxLibModule(MailboxLibModule(customDataDir)).build() + mailboxLibComponent.inject(this) + } + + @Inject + internal lateinit var testSystem: TestSystem + + fun hasExited(): Boolean { + return testSystem.hasExited() + } + + fun getExitCode(): Int { + return testSystem.getExitCode() + } +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/system/ProductionSystem.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/ProductionSystem.kt new file mode 100644 index 0000000000000000000000000000000000000000..2adc532201e5f22eaf226862f755ca837003355c --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/ProductionSystem.kt @@ -0,0 +1,11 @@ +package org.briarproject.mailbox.system + +import org.briarproject.mailbox.core.system.System +import kotlin.system.exitProcess + +internal class ProductionSystem : System { + + override fun exit(code: Int) { + exitProcess(code) + } +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/system/ProductionSystemModule.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/ProductionSystemModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..8137fa1967ecd183bcccbd8bca9ca6ae4d892b63 --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/ProductionSystemModule.kt @@ -0,0 +1,18 @@ +package org.briarproject.mailbox.system + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.briarproject.mailbox.core.system.System +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal class ProductionSystemModule { + + @Singleton + @Provides + fun provideSystem(): System = ProductionSystem() + +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/system/TestSystem.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/TestSystem.kt new file mode 100644 index 0000000000000000000000000000000000000000..ea34f6a3cedf0ddebf1a30d74f1f7ec0d470e8b8 --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/TestSystem.kt @@ -0,0 +1,23 @@ +package org.briarproject.mailbox.system + +import org.briarproject.mailbox.core.system.System + +sealed interface Exited +internal object NotExited : Exited +internal class DidExit(val code: Int) : Exited + +internal class TestSystem(private var exited: Exited = NotExited) : System { + + override fun exit(code: Int) { + exited = DidExit(code) + } + + fun hasExited(): Boolean { + return exited is DidExit + } + + fun getExitCode(): Int { + check(exited is DidExit) + return (exited as DidExit).code + } +} diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/system/TestSystemModule.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/TestSystemModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..b03e0166844129fc48f551c5c80ceda7b7efe9c5 --- /dev/null +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/system/TestSystemModule.kt @@ -0,0 +1,22 @@ +package org.briarproject.mailbox.system + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.briarproject.mailbox.core.system.System +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal class TestSystemModule { + + @Singleton + @Provides + fun provideSystem(system: TestSystem): System = system + + @Singleton + @Provides + fun provideTestSystem(): TestSystem = TestSystem() + +} diff --git a/mailbox-lib/src/test/java/org/briarproject/mailbox/lib/MailboxLibTest.kt b/mailbox-lib/src/test/java/org/briarproject/mailbox/lib/MailboxLibTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f602617ee2f1fc2d0d2a6b8dc2d9b4b9e37d5cc7 --- /dev/null +++ b/mailbox-lib/src/test/java/org/briarproject/mailbox/lib/MailboxLibTest.kt @@ -0,0 +1,42 @@ +/* + * Briar Mailbox + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package org.briarproject.mailbox.lib + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.io.File + +class MailboxLibTest { + + @TempDir + lateinit var mailboxDataDirectory: File + + @Test + fun testStartStopMailbox() { + val mailbox = TestMailbox(mailboxDataDirectory) + mailbox.startLifecycle() + mailbox.waitForTorPublished() + mailbox.stopLifecycle(true) + assertTrue(mailbox.hasExited()) + assertEquals(0, mailbox.getExitCode()) + } +} diff --git a/mailbox-lib/src/test/resources/logback.xml b/mailbox-lib/src/test/resources/logback.xml new file mode 100644 index 0000000000000000000000000000000000000000..2693dcc4b722ef1e36170866d3fbaf4d662639c9 --- /dev/null +++ b/mailbox-lib/src/test/resources/logback.xml @@ -0,0 +1,12 @@ +<configuration> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + <root level="trace"> + <appender-ref ref="STDOUT" /> + </root> + <logger name="org.eclipse.jetty" level="INFO" /> + <logger name="io.netty" level="INFO" /> +</configuration> diff --git a/settings.gradle b/settings.gradle index 8ef7b26e7968e306807f269b864b9a0fb096fee9..072e94e0a70507ae928b0a6220cd318236ab05d7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include ':mailbox-core' include ':mailbox-android' include ':mailbox-cli' +include ':mailbox-lib'