Compare commits

...

13 Commits

Author SHA1 Message Date
Daniel Lublin
fc3fcf120f WIP Add an activity to try out mailbox qr decoding 2021-11-15 14:11:56 +01:00
Daniel Lublin
407ddad0a8 Make it package private 2021-11-15 12:59:57 +01:00
Daniel Lublin
77a986318e Add MailboxPairViewModel that decodes Mailbox QR code 2021-11-15 12:59:56 +01:00
Daniel Lublin
1809be4656 Factor out onion address encoder to CryptoComponent 2021-11-15 12:59:56 +01:00
Daniel Lublin
6d1a0a5792 Refactor qrcode and its camera classes to separate package 2021-11-15 12:59:56 +01:00
akwizgran
8a4fe7ca49 Fix missing import. 2021-11-04 11:08:15 +00:00
akwizgran
e688448537 Merge branch 'dynamic-tor-ports' into 'master'
Make Tor ports configurable at runtime

See merge request briar/briar!1537
2021-11-04 11:00:09 +00:00
Sebastian Kürten
e0f36ade92 Address review feedback 2021-11-03 16:32:17 +01:00
akwizgran
6517f3f2d0 Bump version numbers for 1.4.1 release. 2021-11-03 15:08:52 +00:00
akwizgran
70d5150faf Fix placeholder in Icelandic translation. 2021-11-03 15:08:05 +00:00
Sebastian Kürten
a1f9e80e12 Inject Tor ports via annotated int parameters 2021-11-03 15:43:01 +01:00
Sebastian Kürten
bf091ef854 Use different Tor ports for regular and debug builds 2021-10-16 14:45:14 +02:00
Sebastian Kürten
d4656df384 Make Tor ports configurable at runtime
Instead of using hard-coded values 59050 and 59051 for the Tor socks and
control ports, provide them via a TorPorts interface. This makes it possible
to pass the ports to a TorPortsImpl in modules. Hence it is possible to
configure the Tor port for different types of builds or via command line
options in case of briar headless or other clients using the core code.
2021-10-16 14:41:29 +02:00
41 changed files with 652 additions and 75 deletions

View File

@@ -15,8 +15,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 10400
versionName "1.4.0"
versionCode 10401
versionName "1.4.1"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -70,12 +70,14 @@ class AndroidTorPlugin extends TorPlugin {
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory) {
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture, maxLatency,
maxIdleTime, torDirectory);
maxIdleTime, torDirectory, torSocksPort, torControlPort);
this.app = app;
wakeLock = wakeLockManager.createWakeLock("TorPlugin");
String nativeLibDir = app.getApplicationInfo().nativeLibraryDir;

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
@@ -11,7 +12,9 @@ import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TorControlPort;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
@@ -56,6 +59,9 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final AndroidWakeLockManager wakeLockManager;
private final Clock clock;
private final File torDirectory;
private int torSocksPort;
private int torControlPort;
private final CryptoComponent crypto;
@Inject
AndroidTorPluginFactory(@IoExecutor Executor ioExecutor,
@@ -71,7 +77,10 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Clock clock,
@TorDirectory File torDirectory) {
@TorDirectory File torDirectory,
@TorSocksPort int torSocksPort,
@TorControlPort int torControlPort,
CryptoComponent crypto) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.app = app;
@@ -86,6 +95,9 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.wakeLockManager = wakeLockManager;
this.clock = clock;
this.torDirectory = torDirectory;
this.torSocksPort = torSocksPort;
this.torControlPort = torControlPort;
this.crypto = crypto;
}
@Override
@@ -127,13 +139,15 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
TorRendezvousCrypto torRendezvousCrypto =
new TorRendezvousCryptoImpl(crypto);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor,
wakefulIoExecutor, app, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, wakeLockManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
MAX_LATENCY, MAX_IDLE_TIME, torDirectory, torSocksPort,
torControlPort);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -170,4 +170,11 @@ public interface CryptoComponent {
* length. The line terminator is CRLF.
*/
String asciiArmour(byte[] b, int lineLength);
/**
* Encode the onion/hidden service address given its public key. As
* specified here: https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt?id=29245fd5#n2135
*/
String encodeOnionAddress(byte[] publicKey);
}

View File

@@ -10,8 +10,8 @@ public interface TorConstants {
String PROP_ONION_V2 = "onion";
String PROP_ONION_V3 = "onion3";
int SOCKS_PORT = 59050;
int CONTROL_PORT = 59051;
int DEFAULT_SOCKS_PORT = 59050;
int DEFAULT_CONTROL_PORT = 59051;
int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.plugin;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the control port for the Tor plugin.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface TorControlPort {
}

View File

@@ -0,0 +1,20 @@
package org.briarproject.bramble.api.plugin;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the socks port for the Tor plugin.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface TorSocksPort {
}

View File

@@ -7,6 +7,7 @@ import net.i2p.crypto.eddsa.KeyPairGenerator;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.digests.SHA3Digest;
import org.briarproject.bramble.api.crypto.AgreementPrivateKey;
import org.briarproject.bramble.api.crypto.AgreementPublicKey;
import org.briarproject.bramble.api.crypto.CryptoComponent;
@@ -21,11 +22,13 @@ import org.briarproject.bramble.api.crypto.SignaturePrivateKey;
import org.briarproject.bramble.api.crypto.SignaturePublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import org.briarproject.bramble.util.Base32;
import org.briarproject.bramble.util.ByteUtils;
import org.briarproject.bramble.util.StringUtils;
import org.whispersystems.curve25519.Curve25519;
import org.whispersystems.curve25519.Curve25519KeyPair;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
@@ -58,6 +61,8 @@ class CryptoComponentImpl implements CryptoComponent {
private static final int PBKDF_SALT_BYTES = 32; // 256 bits
private static final byte PBKDF_FORMAT_SCRYPT = 0;
private static final byte PBKDF_FORMAT_SCRYPT_STRENGTHENED = 1;
private static final byte ONION_HS_PROTOCOL_VERSION = 3;
private static final int ONION_CHECKSUM_BYTES = 2;
private final SecureRandom secureRandom;
private final PasswordBasedKdf passwordBasedKdf;
@@ -442,4 +447,21 @@ class CryptoComponentImpl implements CryptoComponent {
public String asciiArmour(byte[] b, int lineLength) {
return AsciiArmour.wrap(b, lineLength);
}
@Override
public String encodeOnionAddress(byte[] publicKey) {
Digest digest = new SHA3Digest(256);
byte[] label = ".onion checksum".getBytes(Charset.forName("US-ASCII"));
digest.update(label, 0, label.length);
digest.update(publicKey, 0, publicKey.length);
digest.update(ONION_HS_PROTOCOL_VERSION);
byte[] checksum = new byte[digest.getDigestSize()];
digest.doFinal(checksum, 0);
byte[] address = new byte[publicKey.length + ONION_CHECKSUM_BYTES + 1];
arraycopy(publicKey, 0, address, 0, publicKey.length);
arraycopy(checksum, 0, address, publicKey.length, ONION_CHECKSUM_BYTES);
address[address.length - 1] = ONION_HS_PROTOCOL_VERSION;
return Base32.encode(address).toLowerCase();
}
}

View File

@@ -34,6 +34,7 @@ import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
@@ -44,6 +45,7 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -68,13 +70,11 @@ import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_PREF_TOR_MOBILE;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_PREF_TOR_NETWORK;
@@ -132,8 +132,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final CircumventionProvider circumventionProvider;
private final ResourceProvider resourceProvider;
private final long maxLatency;
private final int maxIdleTime, socketTimeout;
private final int maxIdleTime;
private final int socketTimeout;
private final File torDirectory, geoIpFile, configFile;
private int torSocksPort;
private int torControlPort;
private final File doneFile, cookieFile;
private final AtomicBoolean used = new AtomicBoolean(false);
@@ -162,7 +165,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory) {
File torDirectory,
int torSocksPort,
int torControlPort) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.networkManager = networkManager;
@@ -182,6 +187,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
socketTimeout = Integer.MAX_VALUE;
else socketTimeout = maxIdleTime * 2;
this.torDirectory = torDirectory;
this.torSocksPort = torSocksPort;
this.torControlPort = torControlPort;
geoIpFile = new File(torDirectory, "geoip");
configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done");
@@ -287,7 +294,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
try {
// Open a control connection and authenticate using the cookie file
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
controlSocket = new Socket("127.0.0.1", torControlPort);
controlConnection = new TorControlConnection(controlSocket);
controlConnection.authenticate(read(cookieFile));
// Tell Tor to exit when the control connection is closed
@@ -390,9 +397,23 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return zin;
}
private static void append(StringBuilder strb, String name, int value) {
strb.append(name);
strb.append(" ");
strb.append(value);
strb.append("\n");
}
private InputStream getConfigInputStream() {
ClassLoader cl = getClass().getClassLoader();
return requireNonNull(cl.getResourceAsStream("torrc"));
StringBuilder strb = new StringBuilder();
append(strb, "ControlPort", torControlPort);
append(strb, "CookieAuthentication", 1);
append(strb, "DisableNetwork", 1);
append(strb, "RunAsDaemon", 1);
append(strb, "SafeSocks", 1);
append(strb, "SocksPort", torSocksPort);
return new ByteArrayInputStream(
strb.toString().getBytes(Charset.forName("UTF-8")));
}
private void listFiles(File f) {

View File

@@ -4,39 +4,26 @@ import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.util.encoders.Base64;
import org.briarproject.bramble.util.Base32;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import java.nio.charset.Charset;
import static java.lang.System.arraycopy;
public class TorRendezvousCryptoImpl implements TorRendezvousCrypto {
class TorRendezvousCryptoImpl implements TorRendezvousCrypto {
private static final EdDSANamedCurveSpec CURVE_SPEC =
EdDSANamedCurveTable.getByName("Ed25519");
private static final byte HS_PROTOCOL_VERSION = 3;
private static final int CHECKSUM_BYTES = 2;
private final CryptoComponent crypto;
TorRendezvousCryptoImpl(CryptoComponent crypto) {
this.crypto = crypto;
}
@Override
public String getOnionAddress(byte[] seed) {
EdDSAPrivateKeySpec spec = new EdDSAPrivateKeySpec(seed, CURVE_SPEC);
byte[] publicKey = spec.getA().toByteArray();
Digest digest = new SHA3Digest(256);
byte[] label = ".onion checksum".getBytes(Charset.forName("US-ASCII"));
digest.update(label, 0, label.length);
digest.update(publicKey, 0, publicKey.length);
digest.update(HS_PROTOCOL_VERSION);
byte[] checksum = new byte[digest.getDigestSize()];
digest.doFinal(checksum, 0);
byte[] address = new byte[publicKey.length + CHECKSUM_BYTES + 1];
arraycopy(publicKey, 0, address, 0, publicKey.length);
arraycopy(checksum, 0, address, publicKey.length, CHECKSUM_BYTES);
address[address.length - 1] = HS_PROTOCOL_VERSION;
return Base32.encode(address).toLowerCase();
return crypto.encodeOnionAddress(spec.getA().toByteArray());
}
@Override

View File

@@ -1,5 +1,7 @@
package org.briarproject.bramble.socks;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import java.net.InetSocketAddress;
import javax.net.SocketFactory;
@@ -9,15 +11,14 @@ import dagger.Provides;
import static org.briarproject.bramble.api.plugin.TorConstants.CONNECT_TO_PROXY_TIMEOUT;
import static org.briarproject.bramble.api.plugin.TorConstants.EXTRA_SOCKET_TIMEOUT;
import static org.briarproject.bramble.api.plugin.TorConstants.SOCKS_PORT;
@Module
public class SocksModule {
@Provides
SocketFactory provideTorSocketFactory() {
SocketFactory provideTorSocketFactory(@TorSocksPort int torSocksPort) {
InetSocketAddress proxy = new InetSocketAddress("127.0.0.1",
SOCKS_PORT);
torSocksPort);
return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT,
EXTRA_SOCKET_TIMEOUT);
}

View File

@@ -1,6 +0,0 @@
ControlPort 59051
CookieAuthentication 1
DisableNetwork 1
RunAsDaemon 1
SafeSocks 1
SocksPort 59050

View File

@@ -35,12 +35,15 @@ abstract class JavaTorPlugin extends TorPlugin {
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory) {
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory);
maxLatency, maxIdleTime, torDirectory, torSocksPort,
torControlPort);
}
@Override

View File

@@ -35,12 +35,15 @@ class UnixTorPlugin extends JavaTorPlugin {
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory) {
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory);
maxLatency, maxIdleTime, torDirectory, torSocksPort,
torControlPort);
}
@Override

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
@@ -9,7 +10,9 @@ import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TorControlPort;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
@@ -54,6 +57,9 @@ public class UnixTorPluginFactory implements DuplexPluginFactory {
private final BatteryManager batteryManager;
private final Clock clock;
private final File torDirectory;
private int torSocksPort;
private int torControlPort;
private final CryptoComponent crypto;
@Inject
UnixTorPluginFactory(@IoExecutor Executor ioExecutor,
@@ -67,7 +73,10 @@ public class UnixTorPluginFactory implements DuplexPluginFactory {
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Clock clock,
@TorDirectory File torDirectory) {
@TorDirectory File torDirectory,
@TorSocksPort int torSocksPort,
@TorControlPort int torControlPort,
CryptoComponent crypto) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.networkManager = networkManager;
@@ -80,6 +89,9 @@ public class UnixTorPluginFactory implements DuplexPluginFactory {
this.batteryManager = batteryManager;
this.clock = clock;
this.torDirectory = torDirectory;
this.torSocksPort = torSocksPort;
this.torControlPort = torControlPort;
this.crypto = crypto;
}
@Override
@@ -120,12 +132,14 @@ public class UnixTorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
TorRendezvousCrypto torRendezvousCrypto =
new TorRendezvousCryptoImpl(crypto);
UnixTorPlugin plugin = new UnixTorPlugin(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, torSocketFactory, clock,
resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
MAX_LATENCY, MAX_IDLE_TIME, torDirectory, torSocksPort,
torControlPort);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
@@ -36,6 +37,8 @@ import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
@@ -86,6 +89,8 @@ public class BridgeTest extends BrambleTestCase {
BackoffFactory backoffFactory;
@Inject
Clock clock;
@Inject
CryptoComponent crypto;
private final File torDir = getTestDirectory();
private final String bridge;
@@ -139,7 +144,8 @@ public class BridgeTest extends BrambleTestCase {
factory = new UnixTorPluginFactory(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, eventBus, torSocketFactory,
backoffFactory, resourceProvider, bridgeProvider,
batteryManager, clock, torDir);
batteryManager, clock, torDir, DEFAULT_SOCKS_PORT,
DEFAULT_CONTROL_PORT, crypto);
}
@After

View File

@@ -26,8 +26,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 10400
versionName "1.4.0"
versionCode 10401
versionName "1.4.1"
applicationId "org.briarproject.briar.android"
vectorDrawables.useSupportLibrary = true

View File

@@ -452,6 +452,15 @@
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
</activity>
<activity
android:name="org.briarproject.briar.android.mailbox.MailboxActivity"
android:label="@string/mailbox_menu_title"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" />
</activity>
<activity
android:name=".android.contact.add.remote.PendingContactListActivity"
android:label="@string/pending_contact_requests"

View File

@@ -18,7 +18,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.LanTcpConstants;
import org.briarproject.bramble.api.plugin.PluginConfig;
import org.briarproject.bramble.api.plugin.TorControlPort;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
@@ -41,6 +43,7 @@ import org.briarproject.briar.android.hotspot.HotspotModule;
import org.briarproject.briar.android.introduction.IntroductionModule;
import org.briarproject.briar.android.logging.LoggingModule;
import org.briarproject.briar.android.login.LoginModule;
import org.briarproject.briar.android.mailbox.MailboxModule;
import org.briarproject.briar.android.navdrawer.NavDrawerModule;
import org.briarproject.briar.android.privategroup.conversation.GroupConversationModule;
import org.briarproject.briar.android.privategroup.list.GroupListModule;
@@ -74,8 +77,11 @@ import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT;
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
@Module(includes = {
SetupModule.class,
@@ -98,6 +104,7 @@ import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBL
SharingModule.class,
HotspotModule.class,
TransferDataModule.class,
MailboxModule.class,
})
public class AppModule {
@@ -154,6 +161,28 @@ public class AppModule {
return app.getDir("tor", MODE_PRIVATE);
}
@Provides
@Singleton
@TorSocksPort
int provideTorSocksPort() {
if (!IS_DEBUG_BUILD) {
return DEFAULT_SOCKS_PORT;
} else {
return DEFAULT_SOCKS_PORT + 2;
}
}
@Provides
@Singleton
@TorControlPort
int provideTorControlPort() {
if (!IS_DEBUG_BUILD) {
return DEFAULT_CONTROL_PORT;
} else {
return DEFAULT_CONTROL_PORT + 2;
}
}
@Provides
@Singleton
PluginConfig providePluginConfig(AndroidBluetoothPluginFactory bluetooth,

View File

@@ -46,6 +46,8 @@ import org.briarproject.briar.android.login.ChangePasswordActivity;
import org.briarproject.briar.android.login.OpenDatabaseFragment;
import org.briarproject.briar.android.login.PasswordFragment;
import org.briarproject.briar.android.login.StartupActivity;
import org.briarproject.briar.android.mailbox.MailboxActivity;
import org.briarproject.briar.android.mailbox.MailboxPairFragment;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.navdrawer.TransportsActivity;
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
@@ -182,6 +184,8 @@ public interface ActivityComponent {
void inject(RemovableDriveActivity activity);
void inject(MailboxActivity activity);
// Fragments
void inject(SetupFragment fragment);
@@ -247,4 +251,6 @@ public interface ActivityComponent {
void inject(RssFeedDeleteFeedDialogFragment fragment);
void inject(ConnectViaBluetoothActivity connectViaBluetoothActivity);
void inject(MailboxPairFragment fragment);
}

View File

@@ -20,6 +20,8 @@ import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgre
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting;
import org.briarproject.briar.android.contact.add.nearby.AddContactState.QrCodeScanned;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.qrcode.CameraException;
import org.briarproject.briar.android.qrcode.CameraView;
import org.briarproject.briar.android.view.QrCodeView;
import java.util.logging.Logger;

View File

@@ -53,7 +53,8 @@ import org.briarproject.briar.android.contact.add.nearby.AddContactState.Contact
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementListening;
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted;
import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting;
import org.briarproject.briar.android.util.QrCodeUtils;
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
import org.briarproject.briar.android.qrcode.QrCodeUtils;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;

View File

@@ -24,7 +24,7 @@ import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.hotspot.HotspotState.NetworkConfig;
import org.briarproject.briar.android.util.QrCodeUtils;
import org.briarproject.briar.android.qrcode.QrCodeUtils;
import java.security.SecureRandom;
import java.util.concurrent.Executor;
@@ -52,7 +52,7 @@ import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.util.QrCodeUtils.HOTSPOT_QRCODE_FACTOR;
import static org.briarproject.briar.android.qrcode.QrCodeUtils.HOTSPOT_QRCODE_FACTOR;
import static org.briarproject.briar.android.util.UiUtils.handleException;
@MethodsNotNullByDefault

View File

@@ -8,7 +8,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.android.hotspot.HotspotState.WebsiteConfig;
import org.briarproject.briar.android.util.QrCodeUtils;
import org.briarproject.briar.android.qrcode.QrCodeUtils;
import java.io.IOException;
import java.net.InetAddress;
@@ -27,7 +27,7 @@ import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.NetworkUtils.getNetworkInterfaces;
import static org.briarproject.briar.android.hotspot.WebServer.PORT;
import static org.briarproject.briar.android.util.QrCodeUtils.HOTSPOT_QRCODE_FACTOR;
import static org.briarproject.briar.android.qrcode.QrCodeUtils.HOTSPOT_QRCODE_FACTOR;
@MethodsNotNullByDefault
@ParametersNotNullByDefault

View File

@@ -0,0 +1,57 @@
package org.briarproject.briar.android.mailbox;
import android.os.Bundle;
import android.view.MenuItem;
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.android.activity.BriarActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.lifecycle.ViewModelProvider;
@RequiresApi(19)
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class MailboxActivity extends BriarActivity implements
BaseFragment.BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
private MailboxPairViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(MailboxPairViewModel.class);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_container);
showInitialFragment(new MailboxPairFragment());
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.briar.android.mailbox;
import org.briarproject.briar.android.viewmodel.ViewModelKey;
import androidx.lifecycle.ViewModel;
import dagger.Binds;
import dagger.Module;
import dagger.multibindings.IntoMap;
@Module
public interface MailboxModule {
@Binds
@IntoMap
@ViewModelKey(MailboxPairViewModel.class)
ViewModel bindMailboxViewModel(
MailboxPairViewModel mailboxPairViewModel);
}

View File

@@ -0,0 +1,139 @@
package org.briarproject.briar.android.mailbox;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
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.android.fragment.BaseFragment;
import org.briarproject.briar.android.qrcode.CameraException;
import org.briarproject.briar.android.qrcode.CameraView;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.annotation.UiThread;
import androidx.lifecycle.ViewModelProvider;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
// TODO have to get camera permission somewhere
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class MailboxPairFragment extends BaseFragment {
static final String TAG = MailboxPairFragment.class.getName();
private static final Logger LOG = Logger.getLogger(TAG);
@Inject
ViewModelProvider.Factory viewModelFactory;
private MailboxPairViewModel viewModel;
private CameraView cameraView;
private View statusView;
private TextView status;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(MailboxPairViewModel.class);
viewModel.getState().observeEvent(this, this::onStateChanged);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_mailbox_qr, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
cameraView = view.findViewById(R.id.camera_view);
cameraView.setPreviewConsumer(viewModel.getQrCodeDecoder());
statusView = view.findViewById(R.id.status_container);
status = view.findViewById(R.id.connect_status);
requireActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
}
private void onStateChanged(MailboxPairViewModel.State state) {
if (state == MailboxPairViewModel.State.QRCODE_VALID ||
state == MailboxPairViewModel.State.QRCODE_INVALID) {
tryStopCamera();
cameraView.setVisibility(INVISIBLE);
statusView.setVisibility(VISIBLE);
CharSequence text = "That's not a valid Mailbox QR code.";
if (state == MailboxPairViewModel.State.QRCODE_VALID) {
String fmt =
"curl -v --socks5-hostname 127.0.0.1:9050" +
" -H \"Authorization: Bearer %s\"" +
" -X PUT http://%s.onion/setup";
text = String.format(fmt, viewModel.getSetupToken(),
viewModel.getOnionAddress());
}
status.setText(text);
}
}
@Override
public void onStart() {
super.onStart();
try {
cameraView.start();
} catch (CameraException e) {
logCameraExceptionAndFinish(e);
}
}
@Override
public void onStop() {
super.onStop();
tryStopCamera();
}
void tryStopCamera() {
try {
cameraView.stop();
} catch (CameraException e) {
logCameraExceptionAndFinish(e);
}
}
@Override
public String getUniqueTag() {
return TAG;
}
@UiThread
private void logCameraExceptionAndFinish(CameraException e) {
logException(LOG, WARNING, e);
Toast.makeText(getActivity(), R.string.camera_error,
LENGTH_LONG).show();
finish();
}
@Override
protected void finish() {
requireActivity().getSupportFragmentManager().popBackStack();
}
}

View File

@@ -0,0 +1,122 @@
package org.briarproject.briar.android.mailbox;
import android.app.Application;
import com.google.zxing.Result;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.android.qrcode.QrCodeDecoder;
import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
@UiThread
@NotNullByDefault
class MailboxPairViewModel extends DbViewModel
implements QrCodeDecoder.ResultCallback {
enum State {QRCODE_VALID, QRCODE_INVALID}
private static final Logger LOG =
getLogger(MailboxPairViewModel.class.getName());
private static final int VERSION_REQUIRED = 32;
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
private final CryptoComponent crypto;
private final MutableLiveEvent<State> state = new MutableLiveEvent<>();
private final QrCodeDecoder qrCodeDecoder;
@Nullable
private String onionAddress = null;
@Nullable
private String setupToken = null;
@Inject
MailboxPairViewModel(
Application app,
@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager,
TransactionManager db,
AndroidExecutor androidExecutor,
@IoExecutor Executor ioExecutor,
CryptoComponent crypto) {
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
this.crypto = crypto;
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
}
@Override
public void onQrCodeDecoded(Result result) {
LOG.info("Got result from decoder");
byte[] bytes = result.getText().getBytes(ISO_8859_1);
if (LOG.isLoggable(INFO))
LOG.info("QR code length in bytes: " + bytes.length);
if (bytes.length != 65) {
LOG.info("QR code has wrong length");
state.postEvent(State.QRCODE_INVALID);
return;
}
if (LOG.isLoggable(INFO))
LOG.info("QR code version: " + bytes[0]);
if (bytes[0] != VERSION_REQUIRED) {
LOG.info("QR code has wrong version");
state.postEvent(State.QRCODE_INVALID);
return;
}
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
onionAddress = crypto.encodeOnionAddress(onionPubKey);
setupToken = StringUtils.toHexString(Arrays.copyOfRange(bytes, 33, 65))
.toLowerCase();
LOG.info("QR code is valid");
state.postEvent(State.QRCODE_VALID);
}
LiveEvent<State> getState() {
return state;
}
QrCodeDecoder getQrCodeDecoder() {
return qrCodeDecoder;
}
String getOnionAddress() {
if (onionAddress == null) {
throw new IllegalStateException();
}
return onionAddress;
}
String getSetupToken() {
if (setupToken == null) {
throw new IllegalStateException();
}
return setupToken;
}
}

View File

@@ -38,6 +38,7 @@ import org.briarproject.briar.android.forum.ForumListFragment;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.logout.SignOutFragment;
import org.briarproject.briar.android.mailbox.MailboxActivity;
import org.briarproject.briar.android.privategroup.list.GroupListFragment;
import org.briarproject.briar.android.settings.SettingsActivity;
@@ -277,6 +278,8 @@ public class NavDrawerActivity extends BriarActivity implements
startActivity(new Intent(this, SettingsActivity.class));
} else if (fragmentId == R.id.nav_btn_signout) {
signOut();
} else if (fragmentId == R.id.nav_btn_mailbox) {
startActivity(new Intent(this, MailboxActivity.class));
}
}

View File

@@ -1,8 +1,8 @@
package org.briarproject.briar.android.contact.add.nearby;
package org.briarproject.briar.android.qrcode;
import java.io.IOException;
class CameraException extends IOException {
public class CameraException extends IOException {
CameraException(String message) {
super(message);

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.contact.add.nearby;
package org.briarproject.briar.android.qrcode;
import android.content.Context;
import android.hardware.Camera;

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.contact.add.nearby;
package org.briarproject.briar.android.qrcode;
import android.hardware.Camera;
@@ -7,7 +7,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import androidx.annotation.UiThread;
@NotNullByDefault
interface PreviewConsumer {
public interface PreviewConsumer {
@UiThread
void start(Camera camera, int cameraIndex);

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.contact.add.nearby;
package org.briarproject.briar.android.qrcode;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
@@ -32,7 +32,7 @@ import static java.util.logging.Logger.getLogger;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
public class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
private static final Logger LOG = getLogger(QrCodeDecoder.class.getName());
@@ -44,7 +44,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
private Camera camera = null;
private int cameraIndex = 0;
QrCodeDecoder(AndroidExecutor androidExecutor,
public QrCodeDecoder(AndroidExecutor androidExecutor,
@IoExecutor Executor ioExecutor, ResultCallback callback) {
this.androidExecutor = androidExecutor;
this.ioExecutor = ioExecutor;
@@ -127,7 +127,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
}
@NotNullByDefault
interface ResultCallback {
public interface ResultCallback {
@IoExecutor
void onQrCodeDecoded(Result result);
}

View File

@@ -1,4 +1,4 @@
package org.briarproject.briar.android.util;
package org.briarproject.briar.android.qrcode;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
@@ -23,11 +23,10 @@ import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
public class QrCodeUtils {
public static final double HOTSPOT_QRCODE_FACTOR = 0.35;
private static final Logger LOG = getLogger(QrCodeUtils.class.getName());
public static final double HOTSPOT_QRCODE_FACTOR = 0.35;
@Nullable
public static Bitmap createQrCode(DisplayMetrics dm, String input) {
return createQrCode(Math.min(dm.widthPixels, dm.heightPixels), input);

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
android:keepScreenOn="true">
<org.briarproject.briar.android.contact.add.nearby.CameraView
<org.briarproject.briar.android.qrcode.CameraView
android:id="@+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<org.briarproject.briar.android.qrcode.CameraView
android:id="@+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/camera_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="vertical">
<LinearLayout
android:id="@+id/status_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/margin_medium"
android:visibility="invisible"
tools:visibility="visible">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/connect_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="@dimen/margin_large"
android:textIsSelectable="true"
tools:text="@string/waiting_for_contact_to_scan" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -37,6 +37,10 @@
android:id="@+id/nav_btn_signout"
android:icon="@drawable/ic_signout"
android:title="@string/sign_out_button" />
<item
android:id="@+id/nav_btn_mailbox"
android:icon="@drawable/ic_crash"
android:title="@string/mailbox_menu_title" />
</group>
</menu>

View File

@@ -689,7 +689,7 @@
<string name="hotspot_error_intro">Eitthvað fór úrskeiðis þegar reynt var að deila forritinu með Wi-Fi:</string>
<string name="hotspot_error_no_wifi_direct">Þetta tæki styður ekki beint Wi-Fi samband.</string>
<string name="hotspot_error_start_callback_failed">Tengipunktur ræstist ekki: villa %s</string>
<string name="hotspot_error_start_callback_failed_unknown">Tengipunktur ræstist ekki vegna óþekktrar villu, ástæðan er %s</string>
<string name="hotspot_error_start_callback_failed_unknown">Tengipunktur ræstist ekki vegna óþekktrar villu, ástæðan er %d</string>
<string name="hotspot_error_start_callback_no_group_info">Tengipunktur ræstist ekki: engar hópupplýsingar</string>
<string name="hotspot_error_web_server_start">Villa við að ræsa vefþjón</string>
<string name="hotspot_flag_test">Aðvörun: Þetta forrit var sett upp með Android Studio og er EKKI hægt að setja upp á öðru tæki.</string>

View File

@@ -805,5 +805,6 @@
<string name="screenshot_message_2">Hi Alice! Thanks for telling me about Briar!</string>
<!-- This is a message to be used in screenshots. -->
<string name="screenshot_message_3">No problem, hope you like it 😀</string>
<string name="mailbox_menu_title">Mailbox</string>
</resources>

View File

@@ -7,7 +7,11 @@ import org.briarproject.bramble.account.AccountModule
import org.briarproject.bramble.api.FeatureFlags
import org.briarproject.bramble.api.db.DatabaseConfig
import org.briarproject.bramble.api.plugin.PluginConfig
import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
import org.briarproject.bramble.api.plugin.TorControlPort
import org.briarproject.bramble.api.plugin.TorDirectory
import org.briarproject.bramble.api.plugin.TorSocksPort
import org.briarproject.bramble.api.plugin.TransportId
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
@@ -73,6 +77,14 @@ internal class HeadlessModule(private val appDir: File) {
return File(appDir, "tor")
}
@Provides
@TorSocksPort
internal fun provideTorSocksPort(): Int = DEFAULT_SOCKS_PORT
@Provides
@TorControlPort
internal fun provideTorControlPort(): Int = DEFAULT_CONTROL_PORT
@Provides
@Singleton
internal fun providePluginConfig(tor: UnixTorPluginFactory): PluginConfig {

View File

@@ -6,6 +6,10 @@ import dagger.Provides
import org.briarproject.bramble.account.AccountModule
import org.briarproject.bramble.api.db.DatabaseConfig
import org.briarproject.bramble.api.plugin.PluginConfig
import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
import org.briarproject.bramble.api.plugin.TorControlPort
import org.briarproject.bramble.api.plugin.TorSocksPort
import org.briarproject.bramble.api.plugin.TransportId
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
@@ -64,6 +68,14 @@ internal class HeadlessTestModule(private val appDir: File) {
return HeadlessDatabaseConfig(dbDir, keyDir)
}
@Provides
@TorSocksPort
internal fun provideTorSocksPort(): Int = DEFAULT_SOCKS_PORT
@Provides
@TorControlPort
internal fun provideTorControlPort(): Int = DEFAULT_CONTROL_PORT
@Provides
@Singleton
internal fun providePluginConfig(): PluginConfig {