diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index d539874de0a982e3d650d4d74c8d88251a07105c..ba100da3888e4d506badeca4dffa0501b07d96c7 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -31,3 +31,15 @@ jobs: java-version: '17' - name: Run Gradle tests run: ./gradlew check --info --stacktrace + build-macos: + runs-on: macos-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + - name: Run Gradle tests + run: ./gradlew check --info --stacktrace diff --git a/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/AbstractTorWrapper.java b/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/AbstractTorWrapper.java index b2dbb22f555fa8efd1a887de6c873d59fc7d3d07..99733387dcbe00c9509fa0396df2cc30f53bdc69 100644 --- a/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/AbstractTorWrapper.java +++ b/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/AbstractTorWrapper.java @@ -50,6 +50,7 @@ import static org.briarproject.onionwrapper.TorWrapper.TorState.STARTED; import static org.briarproject.onionwrapper.TorWrapper.TorState.STARTING; import static org.briarproject.onionwrapper.TorWrapper.TorState.STOPPED; import static org.briarproject.onionwrapper.TorWrapper.TorState.STOPPING; +import static org.briarproject.onionwrapper.util.OsUtils.isMac; @InterfaceNotNullByDefault abstract class AbstractTorWrapper implements EventHandler, TorWrapper { @@ -110,6 +111,10 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper { return new File(torDirectory, "tor"); } + protected File getLibEventFile() { + return new File(torDirectory, "libevent-2.1.7.dylib"); + } + @Override public File getObfs4ExecutableFile() { return new File(torDirectory, "obfs4proxy"); @@ -202,6 +207,9 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper { //noinspection ResultOfMethodCallIgnored doneFile.delete(); installTorExecutable(); + if (isMac()) { + installLibEvent(); + } installObfs4Executable(); installSnowflakeExecutable(); extract(getConfigInputStream(), configFile); @@ -225,6 +233,14 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper { if (!torFile.setExecutable(true, true)) throw new IOException(); } + protected void installLibEvent() throws IOException { + if (LOG.isLoggable(INFO)) { + LOG.info("Installing libevent binary for " + architecture); + } + File libEventFile = getLibEventFile(); + extract(getExecutableInputStream("libevent-2.1.7.dylib"), libEventFile); + } + protected void installObfs4Executable() throws IOException { if (LOG.isLoggable(INFO)) { LOG.info("Installing obfs4proxy binary for " + architecture); diff --git a/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/util/OsUtils.java b/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/util/OsUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..67373dd98d64c998410f3a10ff1ca3aa8b27bfb6 --- /dev/null +++ b/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/util/OsUtils.java @@ -0,0 +1,32 @@ +package org.briarproject.onionwrapper.util; + +import org.briarproject.nullsafety.NotNullByDefault; + +import javax.annotation.Nullable; + +import static org.briarproject.onionwrapper.util.StringUtils.startsWithIgnoreCase; + +@NotNullByDefault +public class OsUtils { + + @Nullable + private static final String os = System.getProperty("os.name"); + @Nullable + private static final String vendor = System.getProperty("java.vendor"); + + public static boolean isWindows() { + return os != null && startsWithIgnoreCase(os, "Win"); + } + + public static boolean isMac() { + return os != null && os.equalsIgnoreCase("Mac OS X"); + } + + public static boolean isLinux() { + return os != null && startsWithIgnoreCase(os, "Linux") && !isAndroid(); + } + + public static boolean isAndroid() { + return vendor != null && vendor.contains("Android"); + } +} diff --git a/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/util/StringUtils.java b/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/util/StringUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..8964d41ac5651579eeb80de976ca5d7cd4a0b99d --- /dev/null +++ b/onionwrapper-core/src/main/java/org/briarproject/onionwrapper/util/StringUtils.java @@ -0,0 +1,12 @@ +package org.briarproject.onionwrapper.util; + +import org.briarproject.nullsafety.NotNullByDefault; + +@NotNullByDefault +public class StringUtils { + + // see https://stackoverflow.com/a/38947571 + static boolean startsWithIgnoreCase(String s, String prefix) { + return s.regionMatches(true, 0, prefix, 0, prefix.length()); + } +} diff --git a/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/TestUtils.java b/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/TestUtils.java index 2c6b65e1e62a466edef7e5223ce8691d7983f1a5..82ad9bd63cb4b0ac45b8635aa52e0ddbf1f38611 100644 --- a/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/TestUtils.java +++ b/onionwrapper-core/src/test/java/org/briarproject/onionwrapper/TestUtils.java @@ -12,7 +12,9 @@ import javax.annotation.concurrent.ThreadSafe; import static java.util.Arrays.asList; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.onionwrapper.StringUtils.startsWithIgnoreCase; +import static org.briarproject.onionwrapper.util.OsUtils.isLinux; +import static org.briarproject.onionwrapper.util.OsUtils.isMac; +import static org.briarproject.onionwrapper.util.OsUtils.isWindows; @ThreadSafe @NotNullByDefault @@ -54,29 +56,18 @@ public class TestUtils { } } - public static boolean isLinux() { - String os = System.getProperty("os.name"); - return os != null && os.contains("Linux"); - } - - public static boolean isWindows() { - String os = System.getProperty("os.name"); - return os != null && startsWithIgnoreCase(os, "Win"); - } - - public static boolean isMac() { - String os = System.getProperty("os.name"); - return os != null && os.equalsIgnoreCase("Mac OS X"); - } - @Nullable public static String getArchitectureForTorBinary() { String arch = System.getProperty("os.arch"); if (arch == null) return null; - //noinspection IfCanBeSwitch - if (arch.equals("amd64")) return "x86_64"; - else if (arch.equals("aarch64")) return "aarch64"; - else if (arch.equals("arm")) return "armhf"; + if (isLinux() || isWindows()) { + //noinspection IfCanBeSwitch + if (arch.equals("amd64")) return "x86_64"; + else if (arch.equals("aarch64")) return "aarch64"; + else if (arch.equals("arm")) return "armhf"; + } else if (isMac()) { + return "any"; + } return null; } diff --git a/onionwrapper-java/build.gradle b/onionwrapper-java/build.gradle index 913f000b25e6e8ecdefdbca470d2a10acf790042..0226df4eb2ec4129cd48c5e5427bb898a87d5498 100644 --- a/onionwrapper-java/build.gradle +++ b/onionwrapper-java/build.gradle @@ -1,5 +1,4 @@ -import static org.briarproject.onionwrapper.OS.Linux -import static org.briarproject.onionwrapper.OS.Windows +import static org.briarproject.onionwrapper.OS.* import static org.briarproject.onionwrapper.OsUtils.currentOS plugins { @@ -19,7 +18,7 @@ checkstyle { dependencies { api project(':onionwrapper-core') - def jna_version = '4.5.2' + def jna_version = '5.10.0' implementation "net.java.dev.jna:jna:$jna_version" implementation "net.java.dev.jna:jna-platform:$jna_version" @@ -29,6 +28,10 @@ dependencies { testImplementation "org.briarproject:tor-$currentOS.id:0.4.7.13-2" testImplementation "org.briarproject:obfs4proxy-$currentOS.id:0.0.14-tor2" testImplementation "org.briarproject:snowflake-$currentOS.id:2.5.1" + } else if (currentOS == MacOS) { + testImplementation "org.briarproject:tor-macos-torbrowser:0.4.7.13" + testImplementation "org.briarproject:obfs4proxy-macos-torbrowser:0.0.14" + testImplementation "org.briarproject:snowflake-macos-torbrowser:2.5.1" } } diff --git a/onionwrapper-java/src/main/java/org/briarproject/onionwrapper/UnixTorWrapper.java b/onionwrapper-java/src/main/java/org/briarproject/onionwrapper/UnixTorWrapper.java index 3d196f98b70d07ae31bb81628d6644121fceea8d..eaea8158d4a93892141cf84186f37ae788d2a190 100644 --- a/onionwrapper-java/src/main/java/org/briarproject/onionwrapper/UnixTorWrapper.java +++ b/onionwrapper-java/src/main/java/org/briarproject/onionwrapper/UnixTorWrapper.java @@ -46,7 +46,7 @@ public class UnixTorWrapper extends JavaTorWrapper { private interface CLibrary extends Library { - CLibrary INSTANCE = Native.loadLibrary("c", CLibrary.class); + CLibrary INSTANCE = Native.load("c", CLibrary.class); int getpid(); } diff --git a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BootstrapTest.java b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BootstrapTest.java index 63d56d87dd83fa4d5a5c0f2a7490d6986ce97625..e8d9cc6ee1334841e7349396ce91f5b677a7b34a 100644 --- a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BootstrapTest.java +++ b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BootstrapTest.java @@ -15,11 +15,12 @@ import static org.briarproject.nullsafety.NullSafety.requireNonNull; import static org.briarproject.onionwrapper.TestUtils.deleteTestDirectory; import static org.briarproject.onionwrapper.TestUtils.getArchitectureForTorBinary; import static org.briarproject.onionwrapper.TestUtils.getTestDirectory; -import static org.briarproject.onionwrapper.TestUtils.isLinux; -import static org.briarproject.onionwrapper.TestUtils.isWindows; import static org.briarproject.onionwrapper.TorWrapper.TorState.CONNECTED; import static org.briarproject.onionwrapper.TorWrapper.TorState.STARTED; import static org.briarproject.onionwrapper.TorWrapper.TorState.STOPPED; +import static org.briarproject.onionwrapper.util.OsUtils.isLinux; +import static org.briarproject.onionwrapper.util.OsUtils.isMac; +import static org.briarproject.onionwrapper.util.OsUtils.isWindows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeNotNull; @@ -38,7 +39,7 @@ public class BootstrapTest extends BaseTest { @Before public void setUp() { - assumeTrue(isLinux() || isWindows()); + assumeTrue(isLinux() || isWindows() || isMac()); assumeNotNull(getArchitectureForTorBinary()); } @@ -52,7 +53,7 @@ public class BootstrapTest extends BaseTest { public void testBootstrapping() throws Exception { String architecture = requireNonNull(getArchitectureForTorBinary()); TorWrapper tor; - if (isLinux()) { + if (isLinux() || isMac()) { tor = new UnixTorWrapper(executor, executor, architecture, torDir, CONTROL_PORT, SOCKS_PORT); } else if (isWindows()) { diff --git a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BridgeTest.java b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BridgeTest.java index 1c822f53e62ae7853ae2860b682deaaa03c99000..5401107e5e8f46c82cc2e9562e0db4bba43bf8b8 100644 --- a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BridgeTest.java +++ b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/BridgeTest.java @@ -32,9 +32,9 @@ import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.VAN import static org.briarproject.onionwrapper.TestUtils.deleteTestDirectory; import static org.briarproject.onionwrapper.TestUtils.getArchitectureForTorBinary; import static org.briarproject.onionwrapper.TestUtils.getTestDirectory; -import static org.briarproject.onionwrapper.TestUtils.isLinux; import static org.briarproject.onionwrapper.TestUtils.isOptionalTestEnabled; import static org.briarproject.onionwrapper.TorWrapper.TorState.CONNECTED; +import static org.briarproject.onionwrapper.util.OsUtils.isLinux; import static org.junit.Assert.fail; import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeTrue; diff --git a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesLinuxTest.java b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesLinuxTest.java index 7ebbf50a754d7c948e64041bb33dc630f005f6fb..666f627bd3da974793117229a0feb98de208d195 100644 --- a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesLinuxTest.java +++ b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesLinuxTest.java @@ -3,7 +3,7 @@ package org.briarproject.onionwrapper; import org.junit.Before; import org.junit.Test; -import static org.briarproject.onionwrapper.TestUtils.isLinux; +import static org.briarproject.onionwrapper.util.OsUtils.isLinux; import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; diff --git a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesMacTest.java b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesMacTest.java new file mode 100644 index 0000000000000000000000000000000000000000..884225b9394cd202862053405bc0da5dd5e035f8 --- /dev/null +++ b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesMacTest.java @@ -0,0 +1,42 @@ +package org.briarproject.onionwrapper; + +import org.junit.Before; +import org.junit.Test; + +import static org.briarproject.onionwrapper.util.OsUtils.isMac; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assume.assumeTrue; + +public class ResourcesMacTest { + + @Before + public void setUp() { + assumeTrue(isMac()); + } + + @Test + public void testCanLoadTor() { + testCanLoadResource("any/tor"); + } + + @Test + public void testCanLoadLibEvent() { + testCanLoadResource("any/libevent-2.1.7.dylib"); + } + + @Test + public void testCanLoadObfs4() { + testCanLoadResource("any/obfs4proxy"); + } + + @Test + public void testCanLoadSnowflake() { + testCanLoadResource("any/snowflake"); + } + + private void testCanLoadResource(String name) { + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader(); + assertNotNull(classLoader.getResourceAsStream(name)); + } +} diff --git a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesWindowsTest.java b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesWindowsTest.java index 01a013786170089f6af09618edeb3e3c63c38fa6..51c8ddfac2c66035f88679196fec79b9d5439641 100644 --- a/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesWindowsTest.java +++ b/onionwrapper-java/src/test/java/org/briarproject/onionwrapper/ResourcesWindowsTest.java @@ -3,7 +3,7 @@ package org.briarproject.onionwrapper; import org.junit.Before; import org.junit.Test; -import static org.briarproject.onionwrapper.TestUtils.isWindows; +import static org.briarproject.onionwrapper.util.OsUtils.isWindows; import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; diff --git a/settings.gradle b/settings.gradle index 2bb9f2af6e7be08bf5b012a9037f63195f94ac9f..7412b9f092671aad1fc05449707410ebb051f8aa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url "https://mvntmp.mobanisto.de" } } } rootProject.name = "Onion Wrapper"