diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java index 6d391e5ec..f3dbdc6b8 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidResourceProvider.java @@ -24,6 +24,7 @@ class AndroidResourceProvider implements ResourceProvider { @Override public InputStream getResourceInputStream(String name) { Resources res = appContext.getResources(); + if (name.endsWith(".zip")) name = name.substring(0, name.length() - 4); int resId = res.getIdentifier(name, "raw", appContext.getPackageName()); return res.openRawResource(resId); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java index 8396dd774..57c3b5ca8 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java @@ -1,7 +1,6 @@ package org.briarproject.bramble.plugin.tor; import org.briarproject.bramble.api.lifecycle.IoExecutor; -import org.briarproject.bramble.api.system.ResourceProvider; import java.io.InputStream; import java.util.ArrayList; @@ -24,14 +23,11 @@ class CircumventionProviderImpl implements CircumventionProvider { private static final Set BRIDGES_WORK_IN_COUNTRIES = new HashSet<>(asList(BRIDGES)); - private final ResourceProvider resourceProvider; - @Nullable private volatile List bridges = null; @Inject - CircumventionProviderImpl(ResourceProvider resourceProvider) { - this.resourceProvider = resourceProvider; + CircumventionProviderImpl() { } @Override @@ -50,8 +46,8 @@ class CircumventionProviderImpl implements CircumventionProvider { List bridges = this.bridges; if (bridges != null) return new ArrayList<>(bridges); - InputStream is = - resourceProvider.getResourceInputStream(BRIDGE_FILE_NAME); + InputStream is = getClass().getClassLoader() + .getResourceAsStream(BRIDGE_FILE_NAME); Scanner scanner = new Scanner(is); bridges = new ArrayList<>(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 87458806a..b1028d0b6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -288,22 +288,22 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private InputStream getTorInputStream() throws IOException { if (LOG.isLoggable(INFO)) LOG.info("Installing Tor binary for " + architecture); - InputStream in = - resourceProvider.getResourceInputStream("tor_" + architecture); + InputStream in = resourceProvider + .getResourceInputStream("tor_" + architecture + ".zip"); ZipInputStream zin = new ZipInputStream(in); if (zin.getNextEntry() == null) throw new IOException(); return zin; } private InputStream getGeoIpInputStream() throws IOException { - InputStream in = resourceProvider.getResourceInputStream("geoip"); + InputStream in = resourceProvider.getResourceInputStream("geoip.zip"); ZipInputStream zin = new ZipInputStream(in); if (zin.getNextEntry() == null) throw new IOException(); return zin; } private InputStream getConfigInputStream() { - return resourceProvider.getResourceInputStream("torrc"); + return getClass().getClassLoader().getResourceAsStream("torrc"); } private void tryToClose(@Nullable Closeable c) { diff --git a/bramble-android/src/main/res/raw/bridges b/bramble-core/src/main/resources/bridges similarity index 100% rename from bramble-android/src/main/res/raw/bridges rename to bramble-core/src/main/resources/bridges diff --git a/bramble-android/src/main/res/raw/torrc b/bramble-core/src/main/resources/torrc similarity index 100% rename from bramble-android/src/main/res/raw/torrc rename to bramble-core/src/main/resources/torrc diff --git a/bramble-j2se/.gitignore b/bramble-j2se/.gitignore index eeb02632a..c980177e1 100644 --- a/bramble-j2se/.gitignore +++ b/bramble-j2se/.gitignore @@ -1,3 +1,4 @@ bin build .settings +src/main/resources/*.zip \ No newline at end of file diff --git a/bramble-j2se/build.gradle b/bramble-j2se/build.gradle index e77258601..6f6e09d51 100644 --- a/bramble-j2se/build.gradle +++ b/bramble-j2se/build.gradle @@ -7,11 +7,16 @@ apply plugin: 'idea' apply plugin: 'witness' apply from: 'witness.gradle' +configurations { + tor +} + dependencies { implementation project(path: ':bramble-core', configuration: 'default') implementation fileTree(dir: 'libs', include: '*.jar') implementation 'net.java.dev.jna:jna:4.4.0' implementation 'net.java.dev.jna:jna-platform:4.4.0' + tor 'org.briarproject:tor-linux:0.2.9.16@zip' apt 'com.google.dagger:dagger-compiler:2.0.2' @@ -25,6 +30,13 @@ dependencies { testImplementation "org.hamcrest:hamcrest-core:1.3" } +project.afterEvaluate { + copy { + from configurations.tor.collect { zipTree(it) } + into 'src/main/resources' + } +} + tasks.withType(Test) { // Use entropy-gathering device specified on command line, if any systemProperty 'java.security.egd', System.getProperty('java.security.egd') diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/api/ConfigurationManager.java b/bramble-j2se/src/main/java/org/briarproject/bramble/api/ConfigurationManager.java new file mode 100644 index 000000000..e49831dbb --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/api/ConfigurationManager.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.api; + +import java.io.File; + +public interface ConfigurationManager { + + File getAppDir(); + +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java b/bramble-j2se/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java new file mode 100644 index 000000000..926fe8ed9 --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/network/JavaNetworkManager.java @@ -0,0 +1,71 @@ +package org.briarproject.bramble.network; + +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.lifecycle.Service; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.network.NetworkStatus; +import org.briarproject.bramble.api.network.event.NetworkStatusEvent; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; + +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.net.NetworkInterface.getNetworkInterfaces; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +class JavaNetworkManager implements NetworkManager, Service { + + private static final Logger LOG = + Logger.getLogger(JavaNetworkManager.class.getName()); + + private final EventBus eventBus; + + @Inject + JavaNetworkManager(EventBus eventBus) { + this.eventBus = eventBus; + } + + @Override + public void startService() { + eventBus.broadcast(new NetworkStatusEvent(getNetworkStatus())); + } + + @Override + public void stopService() { + } + + @Override + public NetworkStatus getNetworkStatus() { + boolean connected = false; + try { + Enumeration interfaces = getNetworkInterfaces(); + if (interfaces != null) { + while (interfaces.hasMoreElements()) { + NetworkInterface i = interfaces.nextElement(); + if (i.isLoopback()) continue; + if (i.isUp()) { + if (LOG.isLoggable(INFO)) { + LOG.info("Interface " + i.getDisplayName() + + " is up."); + } + connected = true; + break; + } + } + } + } catch (SocketException e) { + logException(LOG, WARNING, e); + } + return new NetworkStatus(connected, false); + } + +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/network/JavaNetworkModule.java b/bramble-j2se/src/main/java/org/briarproject/bramble/network/JavaNetworkModule.java new file mode 100644 index 000000000..3c1b1e279 --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/network/JavaNetworkModule.java @@ -0,0 +1,21 @@ +package org.briarproject.bramble.network; + +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.network.NetworkManager; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class JavaNetworkModule { + + @Provides + @Singleton + NetworkManager provideNetworkManager(LifecycleManager lifecycleManager, + JavaNetworkManager networkManager) { + lifecycleManager.registerService(networkManager); + return networkManager; + } +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java new file mode 100644 index 000000000..6dfadfe73 --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPlugin.java @@ -0,0 +1,55 @@ +package org.briarproject.bramble.plugin.tor; + +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.Executor; + +import javax.net.SocketFactory; + +@NotNullByDefault +class JavaTorPlugin extends TorPlugin { + + JavaTorPlugin(Executor ioExecutor, NetworkManager networkManager, + LocationUtils locationUtils, SocketFactory torSocketFactory, + Clock clock, ResourceProvider resourceProvider, + CircumventionProvider circumventionProvider, Backoff backoff, + DuplexPluginCallback callback, String architecture, int maxLatency, + int maxIdleTime, File torDirectory) { + super(ioExecutor, networkManager, locationUtils, torSocketFactory, + clock, resourceProvider, circumventionProvider, backoff, + callback, architecture, maxLatency, maxIdleTime, torDirectory); + } + + @Override + protected int getProcessId() { + try { + // Java 9: ProcessHandle.current().pid() + return Integer.parseInt( + new File("/proc/self").getCanonicalFile().getName()); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + @Override + protected long getLastUpdateTime() { + try { + URI path = getClass().getProtectionDomain().getCodeSource() + .getLocation().toURI(); + return new File(path).lastModified(); + } catch (URISyntaxException e) { + throw new AssertionError(e); + } + } + +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPluginFactory.java b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPluginFactory.java new file mode 100644 index 000000000..7b5f79bec --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/tor/JavaTorPluginFactory.java @@ -0,0 +1,104 @@ +package org.briarproject.bramble.plugin.tor; + +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.BackoffFactory; +import org.briarproject.bramble.api.plugin.TorConstants; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; +import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; +import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; + +import java.io.File; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.annotation.concurrent.Immutable; +import javax.net.SocketFactory; + +import static org.briarproject.bramble.util.OsUtils.isLinux; + +@Immutable +@NotNullByDefault +public class JavaTorPluginFactory implements DuplexPluginFactory { + + private static final Logger LOG = + Logger.getLogger(JavaTorPluginFactory.class.getName()); + + private static final int MAX_LATENCY = 30 * 1000; // 30 seconds + private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds + private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute + private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins + private static final double BACKOFF_BASE = 1.2; + + private final Executor ioExecutor; + private final NetworkManager networkManager; + private final LocationUtils locationUtils; + private final EventBus eventBus; + private final SocketFactory torSocketFactory; + private final BackoffFactory backoffFactory; + private final ResourceProvider resourceProvider; + private final CircumventionProvider circumventionProvider; + private final Clock clock; + private final File torDirectory; + + public JavaTorPluginFactory(Executor ioExecutor, + NetworkManager networkManager, LocationUtils locationUtils, + EventBus eventBus, SocketFactory torSocketFactory, + BackoffFactory backoffFactory, ResourceProvider resourceProvider, + CircumventionProvider circumventionProvider, Clock clock, + File torDirectory) { + this.ioExecutor = ioExecutor; + this.networkManager = networkManager; + this.locationUtils = locationUtils; + this.eventBus = eventBus; + this.torSocketFactory = torSocketFactory; + this.backoffFactory = backoffFactory; + this.resourceProvider = resourceProvider; + this.circumventionProvider = circumventionProvider; + this.clock = clock; + this.torDirectory = torDirectory; + } + + @Override + public TransportId getId() { + return TorConstants.ID; + } + + @Override + public int getMaxLatency() { + return MAX_LATENCY; + } + + @Override + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { + // Check that we have a Tor binary for this architecture + String architecture = null; + if (isLinux()) { + String arch = System.getProperty("os.arch"); + if (arch.equals("amd64")) { + architecture = "linux-x86_64"; + } + } + if (architecture == null) { + LOG.info("Tor is not supported on this architecture"); + return null; + } + + Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, + MAX_POLLING_INTERVAL, BACKOFF_BASE); + if (!torDirectory.exists()) torDirectory.mkdirs(); + JavaTorPlugin plugin = + new JavaTorPlugin(ioExecutor, networkManager, locationUtils, + torSocketFactory, clock, resourceProvider, + circumventionProvider, backoff, callback, architecture, + MAX_LATENCY, MAX_IDLE_TIME, torDirectory); + eventBus.addListener(plugin); + return plugin; + } +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaLocationUtils.java b/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaLocationUtils.java new file mode 100644 index 000000000..e9aadd8d3 --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaLocationUtils.java @@ -0,0 +1,27 @@ +package org.briarproject.bramble.system; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.LocationUtils; + +import java.util.Locale; +import java.util.logging.Logger; + +import javax.inject.Inject; + +@NotNullByDefault +class JavaLocationUtils implements LocationUtils { + + private static final Logger LOG = + Logger.getLogger(JavaLocationUtils.class.getName()); + + @Inject + JavaLocationUtils() { + } + + @Override + public String getCurrentCountry() { + LOG.info("Using user-defined locale"); + return Locale.getDefault().getCountry(); + } + +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaResourceProvider.java b/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaResourceProvider.java new file mode 100644 index 000000000..7f58b3f7a --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaResourceProvider.java @@ -0,0 +1,21 @@ +package org.briarproject.bramble.system; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.ResourceProvider; + +import java.io.InputStream; + +import javax.inject.Inject; + +@NotNullByDefault +class JavaResourceProvider implements ResourceProvider { + + @Inject + JavaResourceProvider() { + } + + @Override + public InputStream getResourceInputStream(String name) { + return this.getClass().getClassLoader().getResourceAsStream(name); + } +} diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaSystemModule.java b/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaSystemModule.java new file mode 100644 index 000000000..c33192d9b --- /dev/null +++ b/bramble-j2se/src/main/java/org/briarproject/bramble/system/JavaSystemModule.java @@ -0,0 +1,25 @@ +package org.briarproject.bramble.system; + +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.api.system.ResourceProvider; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class JavaSystemModule { + + @Provides + @Singleton + LocationUtils provideLocationUtils(JavaLocationUtils locationUtils) { + return locationUtils; + } + + @Provides + @Singleton + ResourceProvider provideResourceProvider(JavaResourceProvider provider) { + return provider; + } +}