diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt index cdaf7094d917d90da6e6b849dbceb74aed64720f..f76410529e95f78ff31eb806379c7ef970d8dff2 100644 --- a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorModule.kt @@ -30,6 +30,7 @@ import dagger.hilt.components.SingletonComponent import org.briarproject.mailbox.core.event.EventBus import org.briarproject.mailbox.core.lifecycle.IoExecutor import org.briarproject.mailbox.core.lifecycle.LifecycleManager +import org.briarproject.mailbox.core.server.WebServerManager import org.briarproject.mailbox.core.settings.SettingsManager import org.briarproject.mailbox.core.system.AndroidWakeLockManager import org.briarproject.mailbox.core.system.Clock @@ -74,6 +75,7 @@ internal class AndroidTorModule { androidWakeLockManager: AndroidWakeLockManager, lifecycleManager: LifecycleManager, eventBus: EventBus, + webServerManager: WebServerManager, ): TorPlugin = AndroidTorPlugin( ioExecutor, app, @@ -85,8 +87,8 @@ internal class AndroidTorModule { circumventionProvider, androidWakeLockManager, architecture, - app.getDir("tor", Context.MODE_PRIVATE), - ).also { + app.getDir("tor", Context.MODE_PRIVATE) + ) { webServerManager.port }.also { lifecycleManager.registerService(it) eventBus.addListener(it) } diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java index c3e30ca7899531ad78414e1f90f6ca7b8a856e98..92992fb3edf8dc2622296c583d6e92b93d124629 100644 --- a/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java +++ b/mailbox-android/src/main/java/org/briarproject/mailbox/core/tor/AndroidTorPlugin.java @@ -42,6 +42,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; +import java.util.function.IntSupplier; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -76,10 +77,11 @@ public class AndroidTorPlugin extends AbstractTorPlugin { CircumventionProvider circumventionProvider, AndroidWakeLockManager wakeLockManager, @Nullable String architecture, - File torDirectory) { + File torDirectory, + IntSupplier portSupplier) { super(ioExecutor, settingsManager, networkManager, locationUtils, clock, resourceProvider, circumventionProvider, architecture, - torDirectory); + torDirectory, portSupplier); this.ctx = ctx; wakeLock = wakeLockManager.createWakeLock("TorPlugin"); String nativeLibDir = ctx.getApplicationInfo().nativeLibraryDir; diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/WebServerManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/WebServerManager.kt index 3f5114ac0b6298fbddc1a7765de7fdd3fe5d4e95..e9a40f6d97e8396f0f83d82c1705c385b6462290 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/WebServerManager.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/WebServerManager.kt @@ -27,10 +27,10 @@ import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import io.ktor.server.plugins.callloging.CallLogging import io.ktor.server.plugins.contentnegotiation.ContentNegotiation +import kotlinx.coroutines.runBlocking import org.briarproject.mailbox.core.contacts.ContactsManager import org.briarproject.mailbox.core.files.FileRouteManager import org.briarproject.mailbox.core.lifecycle.Service -import org.briarproject.mailbox.core.server.WebServerManager.Companion.PORT import org.briarproject.mailbox.core.settings.MetadataRouteManager import org.briarproject.mailbox.core.setup.SetupRouteManager import org.briarproject.mailbox.core.setup.WipeRouteManager @@ -38,9 +38,10 @@ import javax.inject.Inject import javax.inject.Singleton interface WebServerManager : Service { - companion object { - const val PORT: Int = 8000 - } + /** + * Accessing this can block the current thread until the port chosen by the webserver is known. + */ + val port: Int } @Singleton @@ -54,7 +55,7 @@ internal class WebServerManagerImpl @Inject constructor( ) : WebServerManager { private val server by lazy { - embeddedServer(Netty, PORT, watchPaths = emptyList()) { + embeddedServer(Netty, 0, watchPaths = emptyList()) { install(CallLogging) install(Authentication) { bearer { @@ -73,6 +74,7 @@ internal class WebServerManagerImpl @Inject constructor( configureFilesApi(fileRouteManager) } } + override val port get() = runBlocking { server.resolvedConnectors().first().port } override fun startService() { server.start() diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/AbstractTorPlugin.java b/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/AbstractTorPlugin.java index ad17c5d9eaa5e6c9aed384e830abea5ae989abff..379b19f9bf3d99d38c2ee561351a2dcbaad38ea4 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/AbstractTorPlugin.java +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/tor/AbstractTorPlugin.java @@ -29,7 +29,6 @@ import org.briarproject.mailbox.core.event.Event; import org.briarproject.mailbox.core.event.EventListener; import org.briarproject.mailbox.core.lifecycle.IoExecutor; import org.briarproject.mailbox.core.lifecycle.ServiceException; -import org.briarproject.mailbox.core.server.WebServerManager; import org.briarproject.mailbox.core.settings.Settings; import org.briarproject.mailbox.core.settings.SettingsManager; import org.briarproject.mailbox.core.system.Clock; @@ -55,6 +54,7 @@ import java.util.Map; import java.util.Scanner; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.IntSupplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipInputStream; @@ -113,7 +113,7 @@ public abstract class AbstractTorPlugin */ private static final int HS_DESC_UPLOADS = 1; private final Pattern bootstrapPattern = - Pattern.compile("^Bootstrapped ([0-9]{1,3})%.*$"); + Pattern.compile("^Bootstrapped (\\d{1,3})%.*$"); private final Pattern clockSkewPattern = Pattern.compile("CLOCK_SKEW"); private final Executor ioExecutor; @@ -128,6 +128,7 @@ public abstract class AbstractTorPlugin private final ResourceProvider resourceProvider; private final File torDirectory, configFile; private final File doneFile, cookieFile; + private final IntSupplier portSupplier; private final AtomicBoolean used = new AtomicBoolean(false); protected final PluginState state = new PluginState(); @@ -147,7 +148,8 @@ public abstract class AbstractTorPlugin ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, @Nullable String architecture, - File torDirectory) { + File torDirectory, + IntSupplier portSupplier) { this.ioExecutor = ioExecutor; this.settingsManager = settingsManager; this.networkManager = networkManager; @@ -160,6 +162,7 @@ public abstract class AbstractTorPlugin configFile = new File(torDirectory, "torrc"); doneFile = new File(torDirectory, "done"); cookieFile = new File(torDirectory, ".tor/control_auth_cookie"); + this.portSupplier = portSupplier; // Don't execute more than one connection status check at a time connectionStatusExecutor = new PoliteExecutor("TorPlugin", ioExecutor, 1); @@ -264,8 +267,16 @@ public abstract class AbstractTorPlugin // Check whether we're online updateConnectionStatus(networkManager.getNetworkStatus()); // Create a hidden service if necessary - ioExecutor.execute(() -> publishHiddenService( - String.valueOf(WebServerManager.PORT))); + ioExecutor.execute(() -> { + int port; + try { + port = portSupplier.getAsInt(); + } catch (Exception e) { + throw new AssertionError(e); + } + info(LOG, () -> "Binding hidden service to port: " + port); + publishHiddenService(String.valueOf(port)); + }); } private boolean assetsAreUpToDate() { @@ -290,6 +301,7 @@ public abstract class AbstractTorPlugin } protected void extract(InputStream in, File dest) throws IOException { + @SuppressWarnings("IOStreamConstructor") // not in Java 6 minSdk 16 OutputStream out = new FileOutputStream(dest); copyAndClose(in, out); } diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt index 960874cd8156d7c84da414d9c281237a3510881a..f662e6fb20ddc5b823199f92bab6219ed32c6085 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt @@ -6,6 +6,7 @@ import org.briarproject.mailbox.core.db.DatabaseConfig import org.briarproject.mailbox.core.files.FileManager import org.briarproject.mailbox.core.files.FileProvider import org.briarproject.mailbox.core.lifecycle.LifecycleManager +import org.briarproject.mailbox.core.server.WebServerManager import org.briarproject.mailbox.core.settings.MetadataManager import org.briarproject.mailbox.core.settings.SettingsManager import org.briarproject.mailbox.core.setup.SetupManager @@ -28,5 +29,6 @@ interface TestComponent { fun getDatabase(): Database fun getFileProvider(): FileProvider fun getMetadataManager(): MetadataManager + fun getWebServerManager(): WebServerManager fun getWipeManager(): WipeManager } diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt index d1365003964f9e05559f9524104d48f661541a72..dee124dc9797296b3d0d5e78f1228da9a60c7e5f 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt @@ -15,7 +15,6 @@ import org.briarproject.mailbox.core.TestModule import org.briarproject.mailbox.core.TestUtils.getNewRandomContact import org.briarproject.mailbox.core.TestUtils.getNewRandomId import org.briarproject.mailbox.core.contacts.Contact -import org.briarproject.mailbox.core.server.WebServerManager.Companion.PORT import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeAll @@ -54,11 +53,11 @@ abstract class IntegrationTest(private val installJsonFeature: Boolean = true) { level = LogLevel.ALL } } - protected val baseUrl = "http://127.0.0.1:$PORT" + protected lateinit var baseUrl: String + private set protected val ownerToken = getNewRandomId() protected val token = getNewRandomId() - protected val id = getNewRandomId() protected val contact1 = getNewRandomContact() protected val contact2 = getNewRandomContact() protected var tempDir: File? = null @@ -83,6 +82,7 @@ abstract class IntegrationTest(private val installJsonFeature: Boolean = true) { assertFalse(setupManager.hasDb) lifecycleManager.startServices() lifecycleManager.waitForStartup() + baseUrl = "http://127.0.0.1:${testComponent.getWebServerManager().port}" } @AfterAll diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/WebServerIntegrationTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/WebServerIntegrationTest.kt index 0885c267ff1dacfe3b32ca40d424827e6fe8caf8..785764f2f10560f10c1c8c1598ba6eddd7a83458 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/WebServerIntegrationTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/WebServerIntegrationTest.kt @@ -22,7 +22,6 @@ import io.ktor.server.response.respond import io.ktor.server.routing.post import io.ktor.server.routing.routing import kotlinx.coroutines.runBlocking -import org.briarproject.mailbox.core.server.WebServerManager.Companion.PORT import org.junit.jupiter.api.Test import kotlin.test.assertEquals @@ -43,7 +42,7 @@ class WebServerIntegrationTest : IntegrationTest() { @Test fun testJacksonUnsafeDeserialization(): Unit = runBlocking { - val port = PORT + 1 + val port = 8000 val server = embeddedServer(Netty, port, watchPaths = emptyList()) { install(CallLogging) install(ContentNegotiation) { diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt index 904f84f13efc5ea4849783c2db2233ebd80ed8a1..e74c78256ca62ef8c3cde13740addd74401f0f0c 100644 --- a/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorModule.kt @@ -27,6 +27,7 @@ import org.briarproject.mailbox.core.event.EventBus import org.briarproject.mailbox.core.files.FileProvider import org.briarproject.mailbox.core.lifecycle.IoExecutor import org.briarproject.mailbox.core.lifecycle.LifecycleManager +import org.briarproject.mailbox.core.server.WebServerManager import org.briarproject.mailbox.core.settings.SettingsManager import org.briarproject.mailbox.core.system.Clock import org.briarproject.mailbox.core.system.LocationUtils @@ -67,6 +68,7 @@ class JavaTorModule { lifecycleManager: LifecycleManager, eventBus: EventBus, fileProvider: FileProvider, + webServerManager: WebServerManager, ): TorPlugin { val torDir = File(fileProvider.root, "tor") return JavaTorPlugin( @@ -78,8 +80,8 @@ class JavaTorModule { resourceProvider, circumventionProvider, architecture, - torDir, - ).also { + torDir + ) { webServerManager.port }.also { lifecycleManager.registerService(it) eventBus.addListener(it) } diff --git a/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java index 72eef3529e9c8ab67d131e7a0600bc89a32ff5d5..6681285fecf551ed5ad66518d900a53951ec9ef1 100644 --- a/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java +++ b/mailbox-lib/src/main/java/org/briarproject/mailbox/core/tor/JavaTorPlugin.java @@ -32,6 +32,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.security.CodeSource; import java.util.concurrent.Executor; +import java.util.function.IntSupplier; import javax.annotation.Nullable; @@ -45,10 +46,11 @@ public class JavaTorPlugin extends AbstractTorPlugin { ResourceProvider resourceProvider, CircumventionProvider circumventionProvider, @Nullable String architecture, - File torDirectory) { + File torDirectory, + IntSupplier portSupplier) { super(ioExecutor, settingsManager, networkManager, locationUtils, clock, resourceProvider, circumventionProvider, architecture, - torDirectory); + torDirectory, portSupplier); } @Override