Compare commits

..

1 Commits

Author SHA1 Message Date
akwizgran
b4d0a221a3 Add executor with high and low priority queues. 2019-02-14 14:51:31 +00:00
44 changed files with 287 additions and 375 deletions

View File

@@ -39,6 +39,31 @@
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>

View File

@@ -30,8 +30,8 @@ configurations {
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.5.8@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.9@zip'
tor 'org.briarproject:tor-android:0.3.4.8@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'

View File

@@ -68,8 +68,8 @@ dependencyVerification {
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.9:obfs4proxy-android-0.0.9.zip:9b7e9181535ea8d8bbe8ae6338e08cf4c5fc1e357a779393e0ce49586d459ae0',
'org.briarproject:tor-android:0.3.5.8:tor-android-0.3.5.8.zip:42a13a6f185be1a62f42e3f30ce66a3c099ac5ec890a65e7593111b65b44a54a',
'org.briarproject:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface ContactExchangeListener {
void contactExchangeSucceeded(Author remoteAuthor);
/**
* The exchange failed because the contact already exists.
*/
void duplicateContact(Author remoteAuthor);
/**
* A general failure.
*/
void contactExchangeFailed();
}

View File

@@ -41,7 +41,8 @@ public interface ContactExchangeTask {
/**
* Exchanges contact information with a remote peer.
*/
void startExchange(LocalAuthor localAuthor, SecretKey masterSecret,
void startExchange(ContactExchangeListener listener,
LocalAuthor localAuthor, SecretKey masterSecret,
DuplexTransportConnection conn, TransportId transportId,
boolean alice);
}

View File

@@ -1,32 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public class ContactExchangeFailedEvent extends Event {
@Nullable
private final Author duplicateRemoteAuthor;
public ContactExchangeFailedEvent(@Nullable Author duplicateRemoteAuthor) {
this.duplicateRemoteAuthor = duplicateRemoteAuthor;
}
public ContactExchangeFailedEvent() {
this(null);
}
@Nullable
public Author getDuplicateRemoteAuthor() {
return duplicateRemoteAuthor;
}
public boolean wasDuplicateContact() {
return duplicateRemoteAuthor != null;
}
}

View File

@@ -1,20 +0,0 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public class ContactExchangeSucceededEvent extends Event {
private final Author remoteAuthor;
public ContactExchangeSucceededEvent(Author remoteAuthor) {
this.remoteAuthor = remoteAuthor;
}
public Author getRemoteAuthor() {
return remoteAuthor;
}
}

View File

@@ -0,0 +1,67 @@
package org.briarproject.bramble;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.GuardedBy;
@NotNullByDefault
public class PriorityExecutor {
private final Object lock = new Object();
private final Executor delegate, high, low;
@GuardedBy("lock")
private final Queue<Runnable> highQueue = new LinkedList<>();
@GuardedBy("lock")
private final Queue<Runnable> lowQueue = new LinkedList<>();
@GuardedBy("lock")
private boolean isTaskRunning = false;
public PriorityExecutor(Executor delegate) {
this.delegate = delegate;
high = r -> submit(r, true);
low = r -> submit(r, false);
}
public Executor getHighPriorityExecutor() {
return high;
}
public Executor getLowPriorityExecutor() {
return low;
}
private void submit(Runnable r, boolean isHighPriority) {
Runnable wrapped = () -> {
try {
r.run();
} finally {
scheduleNext();
}
};
synchronized (lock) {
if (!isTaskRunning && highQueue.isEmpty() &&
(isHighPriority || lowQueue.isEmpty())) {
isTaskRunning = true;
delegate.execute(wrapped);
} else if (isHighPriority) {
highQueue.add(wrapped);
} else {
lowQueue.add(wrapped);
}
}
}
private void scheduleNext() {
synchronized (lock) {
Runnable next = highQueue.poll();
if (next == null) next = lowQueue.poll();
if (next == null) isTaskRunning = false;
else delegate.execute(next);
}
}
}

View File

@@ -2,11 +2,10 @@ package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactExchangeListener;
import org.briarproject.bramble.api.contact.ContactExchangeTask;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.data.BdfDictionary;
@@ -14,7 +13,6 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
@@ -65,7 +63,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private final ClientHelper clientHelper;
private final RecordReaderFactory recordReaderFactory;
private final RecordWriterFactory recordWriterFactory;
private final EventBus eventBus;
private final Clock clock;
private final ConnectionManager connectionManager;
private final ContactManager contactManager;
@@ -74,6 +71,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private final StreamReaderFactory streamReaderFactory;
private final StreamWriterFactory streamWriterFactory;
private volatile ContactExchangeListener listener;
private volatile LocalAuthor localAuthor;
private volatile DuplexTransportConnection conn;
private volatile TransportId transportId;
@@ -83,9 +81,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
@Inject
ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper,
RecordReaderFactory recordReaderFactory,
RecordWriterFactory recordWriterFactory, EventBus eventBus,
Clock clock, ConnectionManager connectionManager,
ContactManager contactManager,
RecordWriterFactory recordWriterFactory, Clock clock,
ConnectionManager connectionManager, ContactManager contactManager,
TransportPropertyManager transportPropertyManager,
CryptoComponent crypto, StreamReaderFactory streamReaderFactory,
StreamWriterFactory streamWriterFactory) {
@@ -93,7 +90,6 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
this.clientHelper = clientHelper;
this.recordReaderFactory = recordReaderFactory;
this.recordWriterFactory = recordWriterFactory;
this.eventBus = eventBus;
this.clock = clock;
this.connectionManager = connectionManager;
this.contactManager = contactManager;
@@ -104,9 +100,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
}
@Override
public void startExchange(LocalAuthor localAuthor, SecretKey masterSecret,
public void startExchange(ContactExchangeListener listener,
LocalAuthor localAuthor, SecretKey masterSecret,
DuplexTransportConnection conn, TransportId transportId,
boolean alice) {
this.listener = listener;
this.localAuthor = localAuthor;
this.conn = conn;
this.transportId = transportId;
@@ -125,8 +123,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
out = conn.getWriter().getOutputStream();
} catch (IOException e) {
logException(LOG, WARNING, e);
listener.contactExchangeFailed();
tryToClose(conn);
eventBus.broadcast(new ContactExchangeFailedEvent());
return;
}
@@ -136,7 +134,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
localProperties = transportPropertyManager.getLocalProperties();
} catch (DbException e) {
logException(LOG, WARNING, e);
eventBus.broadcast(new ContactExchangeFailedEvent());
listener.contactExchangeFailed();
tryToClose(conn);
return;
}
@@ -198,7 +196,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
}
} catch (IOException e) {
logException(LOG, WARNING, e);
eventBus.broadcast(new ContactExchangeFailedEvent());
listener.contactExchangeFailed();
tryToClose(conn);
return;
}
@@ -206,7 +204,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
// Verify the contact's signature
if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) {
LOG.warning("Invalid signature");
eventBus.broadcast(new ContactExchangeFailedEvent());
listener.contactExchangeFailed();
tryToClose(conn);
return;
}
@@ -223,17 +221,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
conn);
// Pseudonym exchange succeeded
LOG.info("Pseudonym exchange succeeded");
eventBus.broadcast(
new ContactExchangeSucceededEvent(remoteInfo.author));
listener.contactExchangeSucceeded(remoteInfo.author);
} catch (ContactExistsException e) {
logException(LOG, WARNING, e);
tryToClose(conn);
eventBus.broadcast(
new ContactExchangeFailedEvent(remoteInfo.author));
listener.duplicateContact(remoteInfo.author);
} catch (DbException e) {
logException(LOG, WARNING, e);
tryToClose(conn);
eventBus.broadcast(new ContactExchangeFailedEvent());
listener.contactExchangeFailed();
}
}

View File

@@ -17,24 +17,16 @@ public interface CircumventionProvider {
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
/**
* Countries where obfs4 bridge connection are likely to work.
* Countries where vanilla bridge connection are likely to work.
* Should be a subset of {@link #BLOCKED}.
*/
String[] BRIDGES = { "CN", "IR", "EG", "BY", "TR", "SY", "VE" };
/**
* Countries where obfs4 bridges won't work and meek is needed.
* Should be a subset of {@link #BRIDGES}.
*/
String[] NEEDS_MEEK = {"CN", "IR"};
String[] BRIDGES = { "EG", "BY", "TR", "SY", "VE" };
boolean isTorProbablyBlocked(String countryCode);
boolean doBridgesWork(String countryCode);
boolean needsMeek(String countryCode);
@IoExecutor
List<String> getBridges(boolean meek);
List<String> getBridges();
}

View File

@@ -22,8 +22,6 @@ class CircumventionProviderImpl implements CircumventionProvider {
new HashSet<>(asList(BLOCKED));
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(asList(BRIDGES));
private static final Set<String> BRIDGES_NEED_MEEK =
new HashSet<>(asList(NEEDS_MEEK));
@Nullable
private volatile List<String> bridges = null;
@@ -42,14 +40,9 @@ class CircumventionProviderImpl implements CircumventionProvider {
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
}
@Override
public boolean needsMeek(String countryCode) {
return BRIDGES_NEED_MEEK.contains(countryCode);
}
@Override
@IoExecutor
public List<String> getBridges(boolean useMeek) {
public List<String> getBridges() {
List<String> bridges = this.bridges;
if (bridges != null) return new ArrayList<>(bridges);
@@ -60,8 +53,6 @@ class CircumventionProviderImpl implements CircumventionProvider {
bridges = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
boolean isMeekBridge = line.startsWith("Bridge meek");
if (useMeek && !isMeekBridge || !useMeek && isMeekBridge) continue;
if (!line.startsWith("#")) bridges.add(line);
}
scanner.close();

View File

@@ -470,19 +470,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!enable) callback.transportDisabled();
}
private void enableBridges(boolean enable, boolean needsMeek)
throws IOException {
private void enableBridges(boolean enable) throws IOException {
if (enable) {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
if (needsMeek) {
conf.add("ClientTransportPlugin meek_lite exec " +
obfs4File.getAbsolutePath());
} else {
conf.add("ClientTransportPlugin obfs4 exec " +
obfs4File.getAbsolutePath());
}
conf.addAll(circumventionProvider.getBridges(needsMeek));
conf.add("ClientTransportPlugin obfs4 exec " +
obfs4File.getAbsolutePath());
conf.addAll(circumventionProvider.getBridges());
controlConnection.setConf(conf);
} else {
controlConnection.setConf("UseBridges", "0");
@@ -722,17 +716,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_WITH_BRIDGES ||
(automatic && bridgesWork)) {
if (circumventionProvider.needsMeek(country)) {
LOG.info("Enabling network, using meek bridges");
enableBridges(true, true);
} else {
LOG.info("Enabling network, using obfs4 bridges");
enableBridges(true, false);
}
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Enabling network, not using bridges");
enableBridges(false, false);
enableBridges(false);
enableNetwork(true);
}
if (online && wifi && charging) {

View File

@@ -1,5 +1,4 @@
Bridge obfs4 78.46.188.239:37356 5A2D2F4158D0453E00C7C176978D3F41D69C45DB cert=3c0SwxpOisbohNxEc4tb875RVW8eOu1opRTVXJhafaKA/PNNtI7ElQIVOVZg1AdL5bxGCw iat-mode=0
Bridge obfs4 52.15.78.72:9443 02069A3C5362476936B62BA6F5ACC41ABD573A9B cert=ijYG/OKc7kqu2YzKNFfeXN7/BG2BOgfEP2KyYEiGDQthnHbsOiTWHeIG0WJVW+BckzDgKw iat-mode=0
Bridge obfs4 13.58.29.242:9443 0C58939A77DA6B6B29D4B5236A75865659607AE0 cert=OylWIEHb/ezpq1zWxW0sgKRn+9ARH2eOcQOZ8/Gew+4l+oKOhQ2jUX/Y+FSl61JorXZUWA iat-mode=0
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0
Bridge meek_lite 0.0.2.0:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0

View File

@@ -0,0 +1,86 @@
package org.briarproject.bramble;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import static java.util.Arrays.asList;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class PriorityExecutorTest extends BrambleTestCase {
@Test
public void testHighPriorityTasksAreDelegatedInOrderOfSubmission()
throws Exception {
Executor delegate = newSingleThreadExecutor();
PriorityExecutor priority = new PriorityExecutor(delegate);
Executor high = priority.getHighPriorityExecutor();
testTasksAreDelegatedInOrderOfSubmission(high);
}
@Test
public void testLowPriorityTasksAreDelegatedInOrderOfSubmission()
throws Exception {
Executor delegate = newSingleThreadExecutor();
PriorityExecutor priority = new PriorityExecutor(delegate);
Executor low = priority.getLowPriorityExecutor();
testTasksAreDelegatedInOrderOfSubmission(low);
}
@Test
public void testHighPriorityTasksAreRunFirst() throws Exception {
Executor delegate = newSingleThreadExecutor();
PriorityExecutor priority = new PriorityExecutor(delegate);
Executor high = priority.getHighPriorityExecutor();
Executor low = priority.getLowPriorityExecutor();
// Submit a task that will block, causing other tasks to be queued
CountDownLatch cork = new CountDownLatch(1);
low.execute(() -> {
try {
cork.await();
} catch (InterruptedException e) {
fail();
}
});
// Submit alternating tasks to the high and low priority executors
List<Integer> results = new Vector<>();
CountDownLatch tasksFinished = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
int result = i;
Runnable task = () -> {
results.add(result);
tasksFinished.countDown();
};
if (i % 2 == 0) high.execute(task);
else low.execute(task);
}
// Release the cork and wait for all tasks to finish
cork.countDown();
tasksFinished.await();
// The high-priority tasks should have run before the low-priority tasks
assertEquals(asList(0, 2, 4, 6, 8, 1, 3, 5, 7, 9), results);
}
private void testTasksAreDelegatedInOrderOfSubmission(Executor e)
throws Exception {
List<Integer> results = new Vector<>();
CountDownLatch tasksFinished = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
int result = i;
e.execute(() -> {
results.add(result);
tasksFinished.countDown();
});
}
// Wait for all the tasks to finish
tasksFinished.await();
// The tasks should have run in the order they were submitted
assertEquals(asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), results);
}
}

View File

@@ -16,7 +16,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: '*.jar')
implementation 'net.java.dev.jna:jna:4.5.2'
implementation 'net.java.dev.jna:jna-platform:4.5.2'
tor 'org.briarproject:tor:0.3.5.8@zip'
tor 'org.briarproject:tor:0.3.4.8@zip'
tor 'org.briarproject:obfs4proxy:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'

View File

@@ -44,7 +44,7 @@ public class BridgeTest extends BrambleTestCase {
public static Iterable<String> data() {
BrambleJavaIntegrationTestComponent component =
DaggerBrambleJavaIntegrationTestComponent.builder().build();
return component.getCircumventionProvider().getBridges(false);
return component.getCircumventionProvider().getBridges();
}
private final static long TIMEOUT = SECONDS.toMillis(30);
@@ -104,12 +104,7 @@ public class BridgeTest extends BrambleTestCase {
}
@Override
public boolean needsMeek(String countryCode) {
return false;
}
@Override
public List<String> getBridges(boolean useMeek) {
public List<String> getBridges() {
return singletonList(bridge);
}
};

View File

@@ -21,7 +21,7 @@ dependencyVerification {
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.briarproject:obfs4proxy:0.0.7:obfs4proxy-0.0.7.zip:5b2f693262ce43a7e130f7cc7d5d1617925330640a2eb6d71085e95df8ee0642',
'org.briarproject:tor:0.3.5.8:tor-0.3.5.8.zip:96e83391f01984f28669235fc02fbb0243140a2b3b2c73aeffd0042c8d3ced18',
'org.briarproject:tor:0.3.4.8:tor-0.3.4.8.zip:bc0158c34002f471a4fe14a6a481816c918eb520a220bb027f64be902beb757f',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',

View File

@@ -22,7 +22,6 @@
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
<uses-permission-sdk-23 android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name="org.briarproject.briar.android.BriarApplicationImpl"

View File

@@ -67,10 +67,6 @@ public class ImageActivity extends BriarActivity
final static String NAME = "name";
final static String DATE = "date";
@RequiresApi(api = 16)
private final static int UI_FLAGS_DEFAULT =
SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
@Inject
ViewModelProvider.Factory viewModelFactory;
@@ -142,7 +138,9 @@ public class ImageActivity extends BriarActivity
if (SDK_INT >= 16) {
viewModel.getOnImageClicked().observe(this, this::onImageClicked);
window.getDecorView().setSystemUiVisibility(UI_FLAGS_DEFAULT);
window.getDecorView().setSystemUiVisibility(
SYSTEM_UI_FLAG_LAYOUT_STABLE |
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
@@ -208,16 +206,9 @@ public class ImageActivity extends BriarActivity
@Override
public void onPullComplete() {
showStatusBarBeforeFinishing();
supportFinishAfterTransition();
}
@Override
public void onBackPressed() {
showStatusBarBeforeFinishing();
super.onBackPressed();
}
@RequiresApi(api = 16)
private void onImageClicked(@Nullable Boolean clicked) {
if (clicked != null && clicked) {
@@ -238,8 +229,9 @@ public class ImageActivity extends BriarActivity
@RequiresApi(api = 16)
private void hideSystemUi(View decorView) {
decorView.setSystemUiVisibility(
SYSTEM_UI_FLAG_FULLSCREEN | UI_FLAGS_DEFAULT);
decorView.setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN |
SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
);
appBarLayout.animate()
.translationYBy(-1 * appBarLayout.getHeight())
.alpha(0f)
@@ -249,7 +241,9 @@ public class ImageActivity extends BriarActivity
@RequiresApi(api = 16)
private void showSystemUi(View decorView) {
decorView.setSystemUiVisibility(UI_FLAGS_DEFAULT);
decorView.setSystemUiVisibility(
SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
);
appBarLayout.animate()
.translationYBy(appBarLayout.getHeight())
.alpha(1f)
@@ -257,18 +251,6 @@ public class ImageActivity extends BriarActivity
.start();
}
/**
* If we don't show the status bar again before finishing this activity,
* the return transition will "jump" down the size of the status bar
* when the previous activity (with visible status bar) is shown.
*/
private void showStatusBarBeforeFinishing() {
if (SDK_INT >= 16 && appBarLayout.getVisibility() == GONE) {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(UI_FLAGS_DEFAULT);
}
}
private void showSaveImageDialog() {
OnClickListener okListener = (dialog, which) -> {
if (SDK_INT >= 19) {

View File

@@ -4,12 +4,9 @@ import android.os.Bundle;
import android.support.annotation.UiThread;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.ContactExchangeListener;
import org.briarproject.bramble.api.contact.ContactExchangeTask;
import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent;
import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
@@ -31,7 +28,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class ContactExchangeActivity extends KeyAgreementActivity implements
EventListener {
ContactExchangeListener {
private static final Logger LOG =
Logger.getLogger(ContactExchangeActivity.class.getName());
@@ -53,20 +50,6 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
getSupportActionBar().setTitle(R.string.add_contact_title);
}
@Override
public void onStart() {
super.onStart();
// Listen to updates from contactExchangeTask
eventBus.addListener(this);
}
@Override
protected void onStop() {
super.onStop();
// Stop listen to updates from contactExchangeTask
eventBus.addListener(this);
}
private void startContactExchange(KeyAgreementResult result) {
runOnDbThread(() -> {
LocalAuthor localAuthor;
@@ -80,28 +63,15 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
}
// Exchange contact details
contactExchangeTask.startExchange(localAuthor,
result.getMasterKey(), result.getConnection(),
result.getTransportId(), result.wasAlice());
contactExchangeTask.startExchange(ContactExchangeActivity.this,
localAuthor, result.getMasterKey(),
result.getConnection(), result.getTransportId(),
result.wasAlice());
});
}
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactExchangeSucceededEvent) {
contactExchangeSucceeded(
((ContactExchangeSucceededEvent) e).getRemoteAuthor());
} else if (e instanceof ContactExchangeFailedEvent) {
ContactExchangeFailedEvent fe = (ContactExchangeFailedEvent) e;
if (fe.wasDuplicateContact()) {
duplicateContact(fe.getDuplicateRemoteAuthor());
} else {
contactExchangeFailed();
}
}
}
private void contactExchangeSucceeded(Author remoteAuthor) {
public void contactExchangeSucceeded(Author remoteAuthor) {
runOnUiThreadUnlessDestroyed(() -> {
String contactName = remoteAuthor.getName();
String format = getString(R.string.contact_added_toast);
@@ -112,7 +82,8 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
});
}
private void duplicateContact(Author remoteAuthor) {
@Override
public void duplicateContact(Author remoteAuthor) {
runOnUiThreadUnlessDestroyed(() -> {
String contactName = remoteAuthor.getName();
String format = getString(R.string.contact_already_exists);
@@ -123,7 +94,8 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements
});
}
private void contactExchangeFailed() {
@Override
public void contactExchangeFailed() {
runOnUiThreadUnlessDestroyed(() -> {
showErrorFragment(R.string.connection_error_explanation);
});

View File

@@ -178,14 +178,6 @@ public class GroupActivity extends
} else super.onActivityResult(request, result, data);
}
@Override
public void onItemReceived(GroupMessageItem item) {
super.onItemReceived(item);
if (item instanceof JoinMessageItem) {
if (((JoinMessageItem) item).isInitial()) loadSharingContacts();
}
}
@Override
protected int getMaxTextLength() {
return MAX_GROUP_POST_TEXT_LENGTH;

View File

@@ -7,20 +7,14 @@ import android.view.MenuItem;
import android.widget.TextView;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
import org.briarproject.briar.android.view.BriarRecyclerView;
import org.briarproject.briar.api.privategroup.JoinMessageHeader;
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
import java.util.Collection;
@@ -29,13 +23,10 @@ import javax.inject.Inject;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class GroupMemberListActivity extends BriarActivity
implements EventListener {
public class GroupMemberListActivity extends BriarActivity {
@Inject
GroupMemberListController controller;
@Inject
EventBus eventBus;
private MemberListAdapter adapter;
private BriarRecyclerView list;
@@ -70,50 +61,6 @@ public class GroupMemberListActivity extends BriarActivity
@Override
public void onStart() {
super.onStart();
loadMembers();
eventBus.addListener(this);
list.startPeriodicUpdate();
}
@Override
public void onStop() {
super.onStop();
eventBus.removeListener(this);
list.stopPeriodicUpdate();
}
@Override
public void eventOccurred(Event e) {
if (e instanceof GroupMessageAddedEvent) {
// we can't use GroupInvitationResponseReceivedEvent, because
// a peer only becomes a member after joining the group by message
GroupMessageAddedEvent ge = (GroupMessageAddedEvent) e;
if (ge.getGroupId().equals(groupId) &&
ge.getHeader() instanceof JoinMessageHeader) {
loadMembers();
}
} else if (e instanceof GroupRemovedEvent) {
GroupRemovedEvent g = (GroupRemovedEvent) e;
if (g.getGroup().getId().equals(groupId)) {
runOnUiThreadUnlessDestroyed(
this::supportFinishAfterTransition);
}
}
// TODO ContactConnectedEvent and ContactDisconnectedEvent
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void loadMembers() {
controller.loadMembers(groupId,
new UiResultExceptionHandler<Collection<MemberListItem>, DbException>(
this) {
@@ -127,6 +74,24 @@ public class GroupMemberListActivity extends BriarActivity
handleDbException(exception);
}
});
list.startPeriodicUpdate();
}
@Override
public void onStop() {
super.onStop();
list.stopPeriodicUpdate();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -3,14 +3,11 @@ package org.briarproject.briar.android.sharing;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import java.util.Collection;
@@ -29,19 +26,6 @@ public class BlogSharingStatusActivity extends SharingStatusActivity {
component.inject(this);
}
@Override
public void eventOccurred(Event e) {
super.eventOccurred(e);
if (e instanceof BlogInvitationResponseReceivedEvent) {
BlogInvitationResponseReceivedEvent r =
(BlogInvitationResponseReceivedEvent) e;
BlogInvitationResponse h = r.getMessageHeader();
if (h.getShareableId().equals(getGroupId()) && h.wasAccepted()) {
loadSharedWith();
}
}
}
@Override
int getInfoText() {
return R.string.sharing_status_blog;

View File

@@ -3,14 +3,11 @@ package org.briarproject.briar.android.sharing;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.forum.event.ForumInvitationResponseReceivedEvent;
import java.util.Collection;
@@ -29,19 +26,6 @@ public class ForumSharingStatusActivity extends SharingStatusActivity {
component.inject(this);
}
@Override
public void eventOccurred(Event e) {
super.eventOccurred(e);
if (e instanceof ForumInvitationResponseReceivedEvent) {
ForumInvitationResponseReceivedEvent r =
(ForumInvitationResponseReceivedEvent) e;
ForumInvitationResponse h = r.getMessageHeader();
if (h.getShareableId().equals(getGroupId()) && h.wasAccepted()) {
loadSharedWith();
}
}
}
@Override
int getInfoText() {
return R.string.sharing_status_forum;

View File

@@ -2,7 +2,6 @@ package org.briarproject.briar.android.sharing;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.StringRes;
import android.support.v7.widget.LinearLayoutManager;
import android.view.MenuItem;
@@ -11,19 +10,14 @@ import android.widget.TextView;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.contact.ContactItem;
import org.briarproject.briar.android.view.BriarRecyclerView;
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
import java.util.ArrayList;
import java.util.Collection;
@@ -38,13 +32,10 @@ import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
abstract class SharingStatusActivity extends BriarActivity
implements EventListener {
abstract class SharingStatusActivity extends BriarActivity {
@Inject
ConnectionRegistry connectionRegistry;
@Inject
EventBus eventBus;
private static final Logger LOG =
Logger.getLogger(SharingStatusActivity.class.getName());
@@ -77,7 +68,6 @@ abstract class SharingStatusActivity extends BriarActivity
@Override
public void onStart() {
super.onStart();
eventBus.addListener(this);
loadSharedWith();
}
@@ -85,28 +75,9 @@ abstract class SharingStatusActivity extends BriarActivity
public void onStop() {
super.onStop();
adapter.clear();
eventBus.removeListener(this);
list.showProgressBar();
}
@Override
@CallSuper
public void eventOccurred(Event e) {
if (e instanceof ContactLeftShareableEvent) {
ContactLeftShareableEvent c = (ContactLeftShareableEvent) e;
if (c.getGroupId().equals(getGroupId())) {
loadSharedWith();
}
} else if (e instanceof GroupRemovedEvent) {
GroupRemovedEvent g = (GroupRemovedEvent) e;
if (g.getGroup().getId().equals(getGroupId())) {
runOnUiThreadUnlessDestroyed(
this::supportFinishAfterTransition);
}
}
// TODO ContactConnectedEvent and ContactDisconnectedEvent
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
@@ -129,7 +100,7 @@ abstract class SharingStatusActivity extends BriarActivity
return groupId;
}
protected void loadSharedWith() {
private void loadSharedWith() {
runOnDbThread(() -> {
try {
List<ContactItem> contactItems = new ArrayList<>();
@@ -147,7 +118,6 @@ abstract class SharingStatusActivity extends BriarActivity
private void displaySharedWith(List<ContactItem> contacts) {
runOnUiThreadUnlessDestroyed(() -> {
adapter.clear();
if (contacts.isEmpty()) list.showData();
else adapter.addAll(contacts);
});

View File

@@ -82,11 +82,11 @@
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:layout_marginTop="@dimen/margin_medium"
android:textColor="?android:attr/textColorTertiary"
app:layout_constraintEnd_toStartOf="@+id/removeButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toRightOf="@+id/avatarView"
app:layout_constraintStart_toEndOf="@+id/avatarView"
app:layout_constraintTop_toBottomOf="@+id/messageCountView"
tools:text="This group is empty, but has a long status text"/>
tools:text="@string/groups_group_is_empty"/>
<Button
android:id="@+id/removeButton"
@@ -94,11 +94,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/groups_remove"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/divider"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/statusView"
tools:visibility="visible"/>
tools:visibility="gone"/>
<View
android:id="@+id/divider"

View File

@@ -13,7 +13,7 @@
android:id="@+id/action_group_member_list"
android:icon="@drawable/ic_group_white"
android:title="@string/groups_member_list"
app:showAsAction="never"/>
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_group_reveal"

View File

@@ -1,7 +1,6 @@
package org.briarproject.briar.messaging;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.Contact;
@@ -33,12 +32,11 @@ import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.client.ConversationClientImpl;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -46,7 +44,7 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.Collections.emptyList;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
@Immutable
@@ -221,26 +219,8 @@ class MessagingManagerImpl extends ConversationClientImpl
long timestamp = meta.getLong("timestamp");
boolean local = meta.getBoolean("local");
boolean read = meta.getBoolean("read");
// TODO replace fake attachments by real ones
boolean hasText;
List<AttachmentHeader> attachments;
Random random = new Random(id.hashCode());
if (random.nextBoolean()) {
hasText = random.nextBoolean();
attachments = new ArrayList<>();
int numAttachments = random.nextInt(10) + 1;
for (int i = 0; i < numAttachments; i++) {
byte[] b = new byte[UniqueId.LENGTH];
random.nextBytes(b);
attachments.add(new AttachmentHeader(new MessageId(b),
"image/jpeg"));
}
} else {
hasText = true;
attachments = emptyList();
}
headers.add(new PrivateMessageHeader(id, g, timestamp, local,
read, s.isSent(), s.isSeen(), hasText, attachments));
read, s.isSent(), s.isSeen(), true, emptyList()));
} catch (FormatException e) {
throw new DbException(e);
}
@@ -261,30 +241,11 @@ class MessagingManagerImpl extends ConversationClientImpl
@Override
public Attachment getAttachment(MessageId m) {
// TODO add real implementation
String[] files = new String[] {
// "error_animated.gif",
// "error_high.jpg",
// "error_wide.jpg",
// "error_huge.gif",
// "error_large.gif",
// "error_malformed.jpg",
// "wide.jpg",
// "high.jpg",
// "small.png",
"kitten1.jpg",
"kitten2.jpg",
"kitten3.gif",
"kitten4.jpg",
"kitten5.jpg",
"kitten6.png",
};
int index = Math.abs(m.hashCode() % files.length);
String file = files[index];
getLogger(MessagingManagerImpl.class.getName())
.warning("Loading file: " + file);
InputStream is = getClass().getClassLoader().getResourceAsStream(file);
return new Attachment(new BufferedInputStream(is));
byte[] bytes = fromHexString("89504E470D0A1A0A0000000D49484452" +
"000000010000000108060000001F15C4" +
"890000000A49444154789C6300010000" +
"0500010D0A2DB40000000049454E44AE426082");
return new Attachment(new ByteArrayInputStream(bytes));
}
@Override

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -11,10 +11,6 @@ The REST API peer comes as a `jar` file
and needs a Java Runtime Environment (JRE) that supports at least Java 8.
It currently works only on GNU/Linux operating systems.
To build the `jar` file, you can do this:
$ ./gradlew --configure-on-demand briar-headless:jar
You can start the peer (and its API server) like this:
$ java -jar briar-headless/build/libs/briar-headless.jar