Skip to content
Snippets Groups Projects
Commit d31fa9f7 authored by akwizgran's avatar akwizgran
Browse files

Merge branch 'macos' into 'master'

Add support for macOS

See merge request !2
parents e41a81c4 1150f584
No related branches found
No related tags found
1 merge request!2Add support for macOS
Pipeline #14895 passed
Showing
with 200 additions and 38 deletions
...@@ -31,3 +31,15 @@ jobs: ...@@ -31,3 +31,15 @@ jobs:
java-version: '17' java-version: '17'
- name: Run Gradle tests - name: Run Gradle tests
run: ./gradlew check --info --stacktrace 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
...@@ -72,8 +72,9 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper { ...@@ -72,8 +72,9 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
protected final Executor ioExecutor; protected final Executor ioExecutor;
protected final Executor eventExecutor; protected final Executor eventExecutor;
private final String architecture; protected final String architecture;
private final File torDirectory, configFile, doneFile, cookieFile; protected final File torDirectory;
private final File configFile, doneFile, cookieFile;
private final int torSocksPort; private final int torSocksPort;
private final int torControlPort; private final int torControlPort;
...@@ -243,7 +244,7 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper { ...@@ -243,7 +244,7 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
if (!snowflakeFile.setExecutable(true, true)) throw new IOException(); if (!snowflakeFile.setExecutable(true, true)) throw new IOException();
} }
private InputStream getExecutableInputStream(String basename) { protected InputStream getExecutableInputStream(String basename) {
String ext = getExecutableExtension(); String ext = getExecutableExtension();
return requireNonNull(getResourceInputStream(architecture + "/" + basename, ext)); return requireNonNull(getResourceInputStream(architecture + "/" + basename, ext));
} }
......
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");
}
}
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());
}
}
...@@ -12,7 +12,9 @@ import javax.annotation.concurrent.ThreadSafe; ...@@ -12,7 +12,9 @@ import javax.annotation.concurrent.ThreadSafe;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; 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 @ThreadSafe
@NotNullByDefault @NotNullByDefault
...@@ -54,29 +56,21 @@ public class TestUtils { ...@@ -54,29 +56,21 @@ 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 @Nullable
public static String getArchitectureForTorBinary() { public static String getArchitectureForTorBinary() {
String arch = System.getProperty("os.arch"); String arch = System.getProperty("os.arch");
if (arch == null) return null; if (arch == null) return null;
//noinspection IfCanBeSwitch if (isLinux()) {
if (arch.equals("amd64")) return "x86_64"; //noinspection IfCanBeSwitch
else if (arch.equals("aarch64")) return "aarch64"; if (arch.equals("amd64")) return "x86_64";
else if (arch.equals("arm")) return "armhf"; else if (arch.equals("aarch64")) return "aarch64";
else if (arch.equals("arm")) return "armhf";
} else if (isWindows()) {
if (arch.equals("amd64")) return "x86_64";
} else if (isMac()) {
if (arch.equals("amd64")) return "x86_64";
else if (arch.equals("aarch64")) return "aarch64";
}
return null; return null;
} }
......
import static org.briarproject.onionwrapper.OS.Linux
import static org.briarproject.onionwrapper.OS.Windows
import static org.briarproject.onionwrapper.OsUtils.currentOS import static org.briarproject.onionwrapper.OsUtils.currentOS
plugins { plugins {
...@@ -19,17 +17,15 @@ checkstyle { ...@@ -19,17 +17,15 @@ checkstyle {
dependencies { dependencies {
api project(':onionwrapper-core') api project(':onionwrapper-core')
def jna_version = '4.5.2' def jna_version = '5.13.0'
implementation "net.java.dev.jna:jna:$jna_version" implementation "net.java.dev.jna:jna:$jna_version"
implementation "net.java.dev.jna:jna-platform:$jna_version" implementation "net.java.dev.jna:jna-platform:$jna_version"
testImplementation project(path: ':onionwrapper-core', configuration: 'testOutput') testImplementation project(path: ':onionwrapper-core', configuration: 'testOutput')
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
if (currentOS == Linux || currentOS == Windows) { testImplementation "org.briarproject:tor-$currentOS.id:0.4.7.13-2"
testImplementation "org.briarproject:tor-$currentOS.id:0.4.7.13-2" testImplementation "org.briarproject:obfs4proxy-$currentOS.id:0.0.14-tor2"
testImplementation "org.briarproject:obfs4proxy-$currentOS.id:0.0.14-tor2" testImplementation "org.briarproject:snowflake-$currentOS.id:2.5.1"
testImplementation "org.briarproject:snowflake-$currentOS.id:2.5.1"
}
} }
mavenPublishing { mavenPublishing {
......
package org.briarproject.onionwrapper;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Executor;
import static java.util.logging.Level.INFO;
@NotNullByDefault
public class MacTorWrapper extends UnixTorWrapper {
static final String LIB_EVENT_VERSION = "2.1.7";
/**
* @param ioExecutor The wrapper will use this executor to run IO tasks,
* some of which may run for the lifetime of the wrapper, so the executor
* should have an unlimited thread pool.
* @param eventExecutor The wrapper will use this executor to call the
* {@link Observer observer} (if any). To ensure that events are observed
* in the order they occur, this executor should have a single thread (eg
* the app's main thread).
* @param architecture The processor architecture of the Tor and pluggable
* transport binaries.
* @param torDirectory The directory where the Tor process should keep its
* state.
* @param torSocksPort The port number to use for Tor's SOCKS port.
* @param torControlPort The port number to use for Tor's control port.
*/
public MacTorWrapper(Executor ioExecutor,
Executor eventExecutor,
String architecture,
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, eventExecutor, architecture, torDirectory, torSocksPort, torControlPort);
}
@Override
protected void installTorExecutable() throws IOException {
super.installTorExecutable();
installLibEvent();
}
private void installLibEvent() throws IOException {
if (LOG.isLoggable(INFO)) {
LOG.info("Installing libevent binary for " + architecture);
}
File libEventFile = getLibEventFile();
extract(getExecutableInputStream("libevent-" + LIB_EVENT_VERSION + ".dylib"),
libEventFile);
}
private File getLibEventFile() {
return new File(torDirectory, "libevent-" + LIB_EVENT_VERSION + ".dylib");
}
@Override
protected void extract(InputStream in, File dest) throws IOException {
// Important: delete file to prevent problems on macOS in case the file signature changed
// for binaries.
//noinspection ResultOfMethodCallIgnored
dest.delete();
super.extract(in, dest);
}
}
...@@ -46,7 +46,7 @@ public class UnixTorWrapper extends JavaTorWrapper { ...@@ -46,7 +46,7 @@ public class UnixTorWrapper extends JavaTorWrapper {
private interface CLibrary extends Library { private interface CLibrary extends Library {
CLibrary INSTANCE = Native.loadLibrary("c", CLibrary.class); CLibrary INSTANCE = Native.load("c", CLibrary.class);
int getpid(); int getpid();
} }
......
...@@ -15,11 +15,12 @@ import static org.briarproject.nullsafety.NullSafety.requireNonNull; ...@@ -15,11 +15,12 @@ import static org.briarproject.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.onionwrapper.TestUtils.deleteTestDirectory; import static org.briarproject.onionwrapper.TestUtils.deleteTestDirectory;
import static org.briarproject.onionwrapper.TestUtils.getArchitectureForTorBinary; import static org.briarproject.onionwrapper.TestUtils.getArchitectureForTorBinary;
import static org.briarproject.onionwrapper.TestUtils.getTestDirectory; 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.CONNECTED;
import static org.briarproject.onionwrapper.TorWrapper.TorState.STARTED; import static org.briarproject.onionwrapper.TorWrapper.TorState.STARTED;
import static org.briarproject.onionwrapper.TorWrapper.TorState.STOPPED; 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.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeNotNull;
...@@ -38,7 +39,7 @@ public class BootstrapTest extends BaseTest { ...@@ -38,7 +39,7 @@ public class BootstrapTest extends BaseTest {
@Before @Before
public void setUp() { public void setUp() {
assumeTrue(isLinux() || isWindows()); assumeTrue(isLinux() || isWindows() || isMac());
assumeNotNull(getArchitectureForTorBinary()); assumeNotNull(getArchitectureForTorBinary());
} }
...@@ -55,6 +56,9 @@ public class BootstrapTest extends BaseTest { ...@@ -55,6 +56,9 @@ public class BootstrapTest extends BaseTest {
if (isLinux()) { if (isLinux()) {
tor = new UnixTorWrapper(executor, executor, architecture, torDir, tor = new UnixTorWrapper(executor, executor, architecture, torDir,
CONTROL_PORT, SOCKS_PORT); CONTROL_PORT, SOCKS_PORT);
} else if (isMac()) {
tor = new MacTorWrapper(executor, executor, architecture, torDir,
CONTROL_PORT, SOCKS_PORT);
} else if (isWindows()) { } else if (isWindows()) {
tor = new WindowsTorWrapper(executor, executor, architecture, torDir, tor = new WindowsTorWrapper(executor, executor, architecture, torDir,
CONTROL_PORT, SOCKS_PORT); CONTROL_PORT, SOCKS_PORT);
......
...@@ -32,9 +32,9 @@ import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.VAN ...@@ -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.deleteTestDirectory;
import static org.briarproject.onionwrapper.TestUtils.getArchitectureForTorBinary; import static org.briarproject.onionwrapper.TestUtils.getArchitectureForTorBinary;
import static org.briarproject.onionwrapper.TestUtils.getTestDirectory; 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.TestUtils.isOptionalTestEnabled;
import static org.briarproject.onionwrapper.TorWrapper.TorState.CONNECTED; 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.Assert.fail;
import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
......
...@@ -3,7 +3,7 @@ package org.briarproject.onionwrapper; ...@@ -3,7 +3,7 @@ package org.briarproject.onionwrapper;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
......
package org.briarproject.onionwrapper;
import org.junit.Before;
import org.junit.Test;
import static org.briarproject.onionwrapper.MacTorWrapper.LIB_EVENT_VERSION;
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("x86_64/tor");
}
@Test
public void testCanLoadLibEvent() {
testCanLoadResource("x86_64/libevent-" + LIB_EVENT_VERSION + ".dylib");
}
@Test
public void testCanLoadObfs4() {
testCanLoadResource("x86_64/obfs4proxy");
}
@Test
public void testCanLoadSnowflake() {
testCanLoadResource("x86_64/snowflake");
}
private void testCanLoadResource(String name) {
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
assertNotNull(classLoader.getResourceAsStream(name));
}
}
...@@ -3,7 +3,7 @@ package org.briarproject.onionwrapper; ...@@ -3,7 +3,7 @@ package org.briarproject.onionwrapper;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment