Compare commits

..

21 Commits

Author SHA1 Message Date
Torsten Grote
fa79a31911 Define common library version centrally in top-level build.gradle file
This should make it easier to upgrade libraries in the future and provide
an overview over which versions we are using as well as keep them
consistent throughout the project.
2017-12-01 16:32:02 -02:00
akwizgran
8171dd8bc9 Merge branch 'more-lambdas' into 'master'
Replace a few runnables with lambdas

See merge request !638
2017-12-01 17:42:58 +00:00
Torsten Grote
4b88f0d9f1 Merge branch 'package-name-briar-android' into 'master'
Change package name, bump expiry date

See merge request !637
2017-12-01 16:36:47 +00:00
akwizgran
116419f505 Don't show expiry warning for release builds. 2017-12-01 16:18:47 +00:00
akwizgran
87b2624aa8 Set IS_BETA_BUILD to false. 2017-12-01 16:16:37 +00:00
akwizgran
71fe6f3148 Bump expiry date to 31 December 2018. 2017-12-01 16:11:06 +00:00
akwizgran
21df6cb809 Change package name, version number for release branch. 2017-12-01 15:59:04 +00:00
akwizgran
1f0c385a5c Merge branch '1124-notification-channel-crash' into 'master'
Use NotificationChannel for foreground service to avoid crash on Android 8.1

Closes #1124

See merge request !634
2017-12-01 15:53:05 +00:00
Torsten Grote
986ea05fb2 Use NotificationChannel for foreground service to avoid crash on Android 8.1
This also seems to address #1075 at least on an emulator
2017-12-01 13:44:51 -02:00
akwizgran
030b52261d Replace a few runnables with lambdas. 2017-12-01 14:01:32 +00:00
akwizgran
a50e13c2e3 Merge branch 'transport-property-manager-cleanup' into 'master'
Simplify management of old transport property updates

See merge request !629
2017-11-30 17:46:15 +00:00
akwizgran
c8326103b4 Merge branch 'git-rev-parse-workaround' 2017-11-30 17:39:33 +00:00
Torsten Grote
ddea031cbf Merge branch '1110-signature-labels' into 'master'
Don't use ClientId.toString() for signature labels

Closes #1110

See merge request !631
2017-11-30 17:03:07 +00:00
akwizgran
f0d8532f71 Specify 7 characters for Git revision. 2017-11-30 16:55:41 +00:00
akwizgran
4883d157dc Simplify management of old transport property updates. 2017-11-30 16:43:33 +00:00
akwizgran
a1bec1e927 Merge branch 'ed25519' into 'master'
Add support for Ed25519 signatures

See merge request !627
2017-11-30 16:22:04 +00:00
akwizgran
37d4d79c64 Don't rethrow SignatureException as RuntimeException. 2017-11-29 17:29:32 +00:00
akwizgran
05bc3f6a71 Don't use ClientId.toString() for signature labels. 2017-11-29 16:57:00 +00:00
akwizgran
8b3960781a Fix a typo. 2017-11-23 17:34:40 +00:00
akwizgran
f3de4f53c5 Add ProGuard rule to keep EdDSA classes. 2017-11-23 16:18:30 +00:00
akwizgran
166fc2948c Add support for Ed25519 signatures. 2017-11-23 16:17:41 +00:00
56 changed files with 805 additions and 853 deletions

View File

@@ -12,8 +12,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 1615
versionName "0.16.15"
versionCode 1700
versionName "0.17.0"
consumerProguardFiles 'proguard-rules.txt'
}
@@ -27,7 +27,7 @@ dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation fileTree(dir: 'libs', include: '*.jar')
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
compileOnly 'javax.annotation:jsr250-api:1.0'
}
@@ -43,6 +43,7 @@ dependencyVerification {
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128-runtime.jar:e357a0f1d573c2f702a273992b1b6cb661734f66311854efb3778a888515c5b5',
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128.jar:47b4bec6df11a1118da3953da8b9fa1e7079d6fec857faa1a3cf912e53a6fd4e',
@@ -54,8 +55,6 @@ dependencyVerification {
}
ext.torBinaryDir = 'src/main/res/raw'
ext.torVersion = '0.2.9.12'
ext.geoipVersion = '2017-09-06'
ext.torDownloadUrl = 'https://briarproject.org/build/'
def torBinaries = [

View File

@@ -8,6 +8,8 @@
-dontwarn dagger.**
-dontnote dagger.**
-keep class net.i2p.crypto.eddsa.** { *; }
-dontwarn sun.misc.Unsafe
-dontnote com.google.common.**

View File

@@ -5,15 +5,15 @@ targetCompatibility = 1.8
apply plugin: 'witness'
dependencies {
implementation "com.google.dagger:dagger:2.0.2"
implementation "com.google.dagger:dagger:$daggerVersion"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.jmock:jmock:$jmockVersion"
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
}
dependencyVerification {

View File

@@ -20,6 +20,10 @@ public interface CryptoComponent {
KeyParser getSignatureKeyParser();
KeyPair generateEdKeyPair();
KeyParser getEdKeyParser();
KeyParser getMessageKeyParser();
/**
@@ -61,7 +65,6 @@ public interface CryptoComponent {
* @param ourKeyPair our ephemeral keypair
* @param alice true if ourKeyPair belongs to Alice
* @return the shared secret
* @throws GeneralSecurityException
*/
SecretKey deriveSharedSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
@@ -106,7 +109,6 @@ public interface CryptoComponent {
* @param ourKeyPair our ephemeral keypair
* @param alice true if ourKeyPair belongs to Alice
* @return the shared secret
* @throws GeneralSecurityException
*/
SecretKey deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
boolean alice) throws GeneralSecurityException;
@@ -130,7 +132,7 @@ public interface CryptoComponent {
long streamNumber);
/**
* Signs the given byte[] with the given PrivateKey.
* Signs the given byte[] with the given ECDSA private key.
*
* @param label A label specific to this signature
* to ensure that the signature cannot be repurposed
@@ -139,8 +141,17 @@ public interface CryptoComponent {
throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signedData
* and the given publicKey.
* Signs the given byte[] with the given Ed25519 private key.
*
* @param label A label specific to this signature
* to ensure that the signature cannot be repurposed
*/
byte[] signEd(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signed data
* and the given ECDSA public key.
*
* @param label A label that was specific to this signature
* to ensure that the signature cannot be repurposed
@@ -149,6 +160,17 @@ public interface CryptoComponent {
boolean verify(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException;
/**
* Verifies that the given signature is valid for the signed data
* and the given Ed25519 public key.
*
* @param label A label that was specific to this signature
* to ensure that the signature cannot be repurposed
* @return true if the signature was valid, false otherwise.
*/
boolean verifyEd(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException;
/**
* Returns the hash of the given inputs. The inputs are unambiguously
* combined by prefixing each input with its length.

View File

@@ -36,4 +36,8 @@ public class ClientId implements Comparable<ClientId> {
return id.hashCode();
}
@Override
public String toString() {
return id;
}
}

View File

@@ -11,18 +11,19 @@ dependencies {
implementation 'com.madgag.spongycastle:core:1.58.0.0'
implementation 'com.h2database:h2:1.4.192' // This is the last version that supports Java 1.6
implementation 'org.bitlet:weupnp:0.1.4'
implementation 'net.i2p.crypto:eddsa:0.2.0'
apt 'com.google.dagger:dagger-compiler:2.0.2'
apt "com.google.dagger:dagger-compiler:$daggerVersion"
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.jmock:jmock:$jmockVersion"
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
testApt 'com.google.dagger:dagger-compiler:2.0.2'
testApt "com.google.dagger:dagger-compiler:$daggerVersion"
}
dependencyVerification {
@@ -37,6 +38,7 @@ dependencyVerification {
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'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',

View File

@@ -1,5 +1,9 @@
package org.briarproject.bramble.crypto;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.KeyPairGenerator;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.KeyParser;
@@ -56,6 +60,7 @@ class CryptoComponentImpl implements CryptoComponent {
private static final int AGREEMENT_KEY_PAIR_BITS = 256;
private static final int SIGNATURE_KEY_PAIR_BITS = 256;
private static final int ED_KEY_PAIR_BITS = 256;
private static final int STORAGE_IV_BYTES = 24; // 196 bits
private static final int PBKDF_SALT_BYTES = 32; // 256 bits
private static final int PBKDF_TARGET_MILLIS = 500;
@@ -99,6 +104,8 @@ class CryptoComponentImpl implements CryptoComponent {
private final ECKeyPairGenerator signatureKeyPairGenerator;
private final KeyParser agreementKeyParser, signatureKeyParser;
private final MessageEncrypter messageEncrypter;
private final KeyPairGenerator edKeyPairGenerator;
private final KeyParser edKeyParser;
@Inject
CryptoComponentImpl(SecureRandomProvider secureRandomProvider) {
@@ -132,6 +139,9 @@ class CryptoComponentImpl implements CryptoComponent {
signatureKeyParser = new Sec1KeyParser(PARAMETERS,
SIGNATURE_KEY_PAIR_BITS);
messageEncrypter = new MessageEncrypter(secureRandom);
edKeyPairGenerator = new KeyPairGenerator();
edKeyPairGenerator.initialize(ED_KEY_PAIR_BITS, secureRandom);
edKeyParser = new EdKeyParser();
}
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
@@ -190,6 +200,21 @@ class CryptoComponentImpl implements CryptoComponent {
return secret;
}
@Override
public KeyPair generateEdKeyPair() {
java.security.KeyPair keyPair = edKeyPairGenerator.generateKeyPair();
EdDSAPublicKey edPublicKey = (EdDSAPublicKey) keyPair.getPublic();
PublicKey publicKey = new EdPublicKey(edPublicKey.getAbyte());
EdDSAPrivateKey edPrivateKey = (EdDSAPrivateKey) keyPair.getPrivate();
PrivateKey privateKey = new EdPrivateKey(edPrivateKey.getSeed());
return new KeyPair(publicKey, privateKey);
}
@Override
public KeyParser getEdKeyParser() {
return edKeyParser;
}
@Override
public KeyPair generateAgreementKeyPair() {
AsymmetricCipherKeyPair keyPair =
@@ -416,19 +441,41 @@ class CryptoComponentImpl implements CryptoComponent {
@Override
public byte[] sign(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException {
Signature signature = new SignatureImpl(secureRandom);
KeyParser keyParser = getSignatureKeyParser();
return sign(new SignatureImpl(secureRandom), signatureKeyParser, label,
toSign, privateKey);
}
@Override
public byte[] signEd(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException {
return sign(new EdSignature(), edKeyParser, label, toSign, privateKey);
}
private byte[] sign(Signature sig, KeyParser keyParser, String label,
byte[] toSign, byte[] privateKey) throws GeneralSecurityException {
PrivateKey key = keyParser.parsePrivateKey(privateKey);
signature.initSign(key);
updateSignature(signature, label, toSign);
return signature.sign();
sig.initSign(key);
updateSignature(sig, label, toSign);
return sig.sign();
}
@Override
public boolean verify(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException {
Signature sig = new SignatureImpl(secureRandom);
KeyParser keyParser = getSignatureKeyParser();
return verify(new SignatureImpl(secureRandom), signatureKeyParser,
label, signedData, publicKey, signature);
}
@Override
public boolean verifyEd(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException {
return verify(new EdSignature(), edKeyParser, label, signedData,
publicKey, signature);
}
private boolean verify(Signature sig, KeyParser keyParser, String label,
byte[] signedData, byte[] publicKey, byte[] signature)
throws GeneralSecurityException {
PublicKey key = keyParser.parsePublicKey(publicKey);
sig.initVerify(key);
updateSignature(sig, label, signedData);
@@ -436,7 +483,7 @@ class CryptoComponentImpl implements CryptoComponent {
}
private void updateSignature(Signature signature, String label,
byte[] toSign) {
byte[] toSign) throws GeneralSecurityException {
byte[] labelBytes = StringUtils.toUtf8(label);
byte[] length = new byte[INT_32_BYTES];
ByteUtils.writeUint32(labelBytes.length, length, 0);

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.KeyParser;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException;
@NotNullByDefault
class EdKeyParser implements KeyParser {
@Override
public PublicKey parsePublicKey(byte[] encodedKey)
throws GeneralSecurityException {
if (encodedKey.length != 32) throw new GeneralSecurityException();
return new EdPublicKey(encodedKey);
}
@Override
public PrivateKey parsePrivateKey(byte[] encodedKey)
throws GeneralSecurityException {
if (encodedKey.length != 32) throw new GeneralSecurityException();
return new EdPrivateKey(encodedKey);
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
class EdPrivateKey extends Bytes implements PrivateKey {
EdPrivateKey(byte[] bytes) {
super(bytes);
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
class EdPublicKey extends Bytes implements PublicKey {
EdPublicKey(byte[] bytes) {
super(bytes);
}
@Override
public byte[] getEncoded() {
return getBytes();
}
}

View File

@@ -0,0 +1,83 @@
package org.briarproject.bramble.crypto;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.EdDSASecurityProvider;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import static net.i2p.crypto.eddsa.EdDSAEngine.SIGNATURE_ALGORITHM;
@NotNullByDefault
class EdSignature implements Signature {
private static final Provider PROVIDER = new EdDSASecurityProvider();
private static final EdDSANamedCurveSpec CURVE_SPEC =
EdDSANamedCurveTable.getByName("Ed25519");
private final java.security.Signature signature;
EdSignature() {
try {
signature = java.security.Signature
.getInstance(SIGNATURE_ALGORITHM, PROVIDER);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
@Override
public void initSign(PrivateKey k) throws GeneralSecurityException {
if (!(k instanceof EdPrivateKey))
throw new IllegalArgumentException();
EdDSAPrivateKey privateKey = new EdDSAPrivateKey(
new EdDSAPrivateKeySpec(k.getEncoded(), CURVE_SPEC));
signature.initSign(privateKey);
}
@Override
public void initVerify(PublicKey k) throws GeneralSecurityException {
if (!(k instanceof EdPublicKey))
throw new IllegalArgumentException();
EdDSAPublicKey publicKey = new EdDSAPublicKey(
new EdDSAPublicKeySpec(k.getEncoded(), CURVE_SPEC));
signature.initVerify(publicKey);
}
@Override
public void update(byte b) throws GeneralSecurityException {
signature.update(b);
}
@Override
public void update(byte[] b) throws GeneralSecurityException {
signature.update(b);
}
@Override
public void update(byte[] b, int off, int len)
throws GeneralSecurityException {
signature.update(b, off, len);
}
@Override
public byte[] sign() throws GeneralSecurityException {
return signature.sign();
}
@Override
public boolean verify(byte[] sig) throws GeneralSecurityException {
return signature.verify(sig);
}
}

View File

@@ -22,25 +22,25 @@ interface Signature {
/**
* @see {@link java.security.Signature#update(byte)}
*/
void update(byte b);
void update(byte b) throws GeneralSecurityException;
/**
* @see {@link java.security.Signature#update(byte[])}
*/
void update(byte[] b);
void update(byte[] b) throws GeneralSecurityException;
/**
* @see {@link java.security.Signature#update(byte[], int, int)}
*/
void update(byte[] b, int off, int len);
void update(byte[] b, int off, int len) throws GeneralSecurityException;
/**
* @see {@link java.security.Signature#sign()}
*/
byte[] sign();
byte[] sign() throws GeneralSecurityException;
/**
* @see {@link java.security.Signature#verify(byte[])}
*/
boolean verify(byte[] signature);
boolean verify(byte[] signature) throws GeneralSecurityException;
}

View File

@@ -90,6 +90,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
private final ReentrantReadWriteLock lock =
new ReentrantReadWriteLock(true);
private volatile int shutdownHandle = -1;
@Inject
DatabaseComponentImpl(Database<T> db, Class<T> txnClass, EventBus eventBus,
ShutdownManager shutdown) {
@@ -101,20 +103,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override
public boolean open() throws DbException {
boolean reopened = db.open();
shutdown.addShutdownHook(() -> {
Runnable shutdownHook = () -> {
try {
close();
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
});
};
boolean reopened = db.open();
shutdownHandle = shutdown.addShutdownHook(shutdownHook);
return reopened;
}
@Override
public void close() throws DbException {
if (closed.getAndSet(true)) return;
shutdown.removeShutdownHook(shutdownHandle);
db.close();
}

View File

@@ -129,8 +129,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
public Map<TransportId, TransportProperties> getLocalProperties()
throws DbException {
Map<TransportId, TransportProperties> local;
// TODO: Transaction can be read-only when code is simplified
Transaction txn = db.startTransaction(false);
Transaction txn = db.startTransaction(true);
try {
local = getLocalProperties(txn);
db.commitTransaction(txn);
@@ -165,8 +164,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
throws DbException {
try {
TransportProperties p = null;
// TODO: Transaction can be read-only when code is simplified
Transaction txn = db.startTransaction(false);
Transaction txn = db.startTransaction(true);
try {
// Find the latest local update
LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
@@ -192,8 +190,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
public Map<ContactId, TransportProperties> getRemoteProperties(
TransportId t) throws DbException {
Map<ContactId, TransportProperties> remote = new HashMap<>();
// TODO: Transaction can be read-only when code is simplified
Transaction txn = db.startTransaction(false);
Transaction txn = db.startTransaction(true);
try {
for (Contact c : db.getContacts(txn))
remote.put(c.getId(), getRemoteProperties(txn, c, t));
@@ -227,8 +224,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
throws DbException {
TransportProperties p;
// TODO: Transaction can be read-only when code is simplified
Transaction txn = db.startTransaction(false);
Transaction txn = db.startTransaction(true);
try {
p = getRemoteProperties(txn, db.getContact(txn, c), t);
db.commitTransaction(txn);
@@ -318,7 +314,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
private Map<TransportId, LatestUpdate> findLatestLocal(Transaction txn)
throws DbException, FormatException {
// TODO: This can be simplified before 1.0
Map<TransportId, LatestUpdate> latestUpdates = new HashMap<>();
Map<MessageId, BdfDictionary> metadata = clientHelper
.getMessageMetadataAsDictionary(txn, localGroup.getId());
@@ -326,17 +321,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
BdfDictionary meta = e.getValue();
TransportId t = new TransportId(meta.getString("transportId"));
long version = meta.getLong("version");
LatestUpdate latest = latestUpdates.get(t);
if (latest == null) {
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
} else if (version > latest.version) {
// This update is newer - delete the previous one
db.removeMessage(txn, latest.messageId);
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
} else {
// We've already found a newer update - delete this one
db.removeMessage(txn, e.getKey());
}
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
}
return latestUpdates;
}
@@ -344,38 +329,16 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Nullable
private LatestUpdate findLatest(Transaction txn, GroupId g, TransportId t,
boolean local) throws DbException, FormatException {
// TODO: This can be simplified before 1.0
LatestUpdate latest = null;
Map<MessageId, BdfDictionary> metadata =
clientHelper.getMessageMetadataAsDictionary(txn, g);
for (Entry<MessageId, BdfDictionary> e : metadata.entrySet()) {
BdfDictionary meta = e.getValue();
if (meta.getString("transportId").equals(t.getString())
&& meta.getBoolean("local") == local) {
long version = meta.getLong("version");
if (latest == null) {
latest = new LatestUpdate(e.getKey(), version);
} else if (version > latest.version) {
// This update is newer - delete the previous one
if (local) {
db.removeMessage(txn, latest.messageId);
} else {
db.deleteMessage(txn, latest.messageId);
db.deleteMessageMetadata(txn, latest.messageId);
}
latest = new LatestUpdate(e.getKey(), version);
} else {
// We've already found a newer update - delete this one
if (local) {
db.removeMessage(txn, e.getKey());
} else {
db.deleteMessage(txn, e.getKey());
db.deleteMessageMetadata(txn, e.getKey());
}
}
return new LatestUpdate(e.getKey(), meta.getLong("version"));
}
}
return latest;
return null;
}
private TransportProperties parseProperties(BdfList message)

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.KeyPair;
import java.security.GeneralSecurityException;
public class EcdsaSignatureTest extends SignatureTest {
@Override
protected KeyPair generateKeyPair() {
return crypto.generateSignatureKeyPair();
}
@Override
protected byte[] sign(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException {
return crypto.sign(label, toSign, privateKey);
}
@Override
protected boolean verify(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException {
return crypto.verify(label, signedData, publicKey, signature);
}
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.crypto;
import org.briarproject.bramble.api.crypto.KeyPair;
import java.security.GeneralSecurityException;
public class EdSignatureTest extends SignatureTest {
@Override
protected KeyPair generateKeyPair() {
return crypto.generateEdKeyPair();
}
@Override
protected byte[] sign(String label, byte[] toSign, byte[] privateKey)
throws GeneralSecurityException {
return crypto.signEd(label, toSign, privateKey);
}
@Override
protected boolean verify(String label, byte[] signedData, byte[] publicKey,
byte[] signature) throws GeneralSecurityException {
return crypto.verifyEd(label, signedData, publicKey, signature);
}
}

View File

@@ -8,23 +8,32 @@ import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.util.StringUtils;
import org.junit.Test;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class SignatureTest extends BrambleTestCase {
public abstract class SignatureTest extends BrambleTestCase {
private final CryptoComponent crypto;
protected final CryptoComponent crypto;
private final byte[] publicKey, privateKey;
private final String label = StringUtils.getRandomString(42);
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
public SignatureTest() {
protected abstract KeyPair generateKeyPair();
protected abstract byte[] sign(String label, byte[] toSign,
byte[] privateKey) throws GeneralSecurityException;
protected abstract boolean verify(String label, byte[] signedData,
byte[] publicKey, byte[] signature) throws GeneralSecurityException;
SignatureTest() {
crypto = new CryptoComponentImpl(new TestSecureRandomProvider());
KeyPair k = crypto.generateSignatureKeyPair();
KeyPair k = generateKeyPair();
publicKey = k.getPublic().getEncoded();
privateKey = k.getPrivate().getEncoded();
}
@@ -33,19 +42,19 @@ public class SignatureTest extends BrambleTestCase {
public void testIdenticalKeysAndInputsProduceIdenticalSignatures()
throws Exception {
// Calculate the Signature twice - the results should be identical
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
byte[] sig2 = crypto.sign(label, inputBytes, privateKey);
byte[] sig1 = sign(label, inputBytes, privateKey);
byte[] sig2 = sign(label, inputBytes, privateKey);
assertArrayEquals(sig1, sig2);
}
@Test
public void testDifferentKeysProduceDifferentSignatures() throws Exception {
// Generate second private key
KeyPair k2 = crypto.generateSignatureKeyPair();
KeyPair k2 = generateKeyPair();
byte[] privateKey2 = k2.getPrivate().getEncoded();
// Calculate the signature with each key
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
byte[] sig2 = crypto.sign(label, inputBytes, privateKey2);
byte[] sig1 = sign(label, inputBytes, privateKey);
byte[] sig2 = sign(label, inputBytes, privateKey2);
assertFalse(Arrays.equals(sig1, sig2));
}
@@ -56,8 +65,8 @@ public class SignatureTest extends BrambleTestCase {
byte[] inputBytes2 = TestUtils.getRandomBytes(123);
// Calculate the signature with different inputs
// the results should be different
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
byte[] sig2 = crypto.sign(label, inputBytes2, privateKey);
byte[] sig1 = sign(label, inputBytes, privateKey);
byte[] sig2 = sign(label, inputBytes2, privateKey);
assertFalse(Arrays.equals(sig1, sig2));
}
@@ -68,25 +77,25 @@ public class SignatureTest extends BrambleTestCase {
String label2 = StringUtils.getRandomString(42);
// Calculate the signature with different inputs
// the results should be different
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
byte[] sig2 = crypto.sign(label2, inputBytes, privateKey);
byte[] sig1 = sign(label, inputBytes, privateKey);
byte[] sig2 = sign(label2, inputBytes, privateKey);
assertFalse(Arrays.equals(sig1, sig2));
}
@Test
public void testSignatureVerification() throws Exception {
byte[] sig = crypto.sign(label, inputBytes, privateKey);
assertTrue(crypto.verify(label, inputBytes, publicKey, sig));
byte[] sig = sign(label, inputBytes, privateKey);
assertTrue(verify(label, inputBytes, publicKey, sig));
}
@Test
public void testDifferentKeyFailsVerification() throws Exception {
// Generate second private key
KeyPair k2 = crypto.generateSignatureKeyPair();
KeyPair k2 = generateKeyPair();
byte[] privateKey2 = k2.getPrivate().getEncoded();
// calculate the signature with different key, should fail to verify
byte[] sig = crypto.sign(label, inputBytes, privateKey2);
assertFalse(crypto.verify(label, inputBytes, publicKey, sig));
byte[] sig = sign(label, inputBytes, privateKey2);
assertFalse(verify(label, inputBytes, publicKey, sig));
}
@Test
@@ -94,8 +103,8 @@ public class SignatureTest extends BrambleTestCase {
// Generate a second input
byte[] inputBytes2 = TestUtils.getRandomBytes(123);
// calculate the signature with different input, should fail to verify
byte[] sig = crypto.sign(label, inputBytes, privateKey);
assertFalse(crypto.verify(label, inputBytes2, publicKey, sig));
byte[] sig = sign(label, inputBytes, privateKey);
assertFalse(verify(label, inputBytes2, publicKey, sig));
}
@Test
@@ -103,8 +112,8 @@ public class SignatureTest extends BrambleTestCase {
// Generate a second label
String label2 = StringUtils.getRandomString(42);
// calculate the signature with different label, should fail to verify
byte[] sig = crypto.sign(label, inputBytes, privateKey);
assertFalse(crypto.verify(label2, inputBytes, publicKey, sig));
byte[] sig = sign(label, inputBytes, privateKey);
assertFalse(verify(label2, inputBytes, publicKey, sig));
}
}

View File

@@ -47,10 +47,11 @@ import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.OutgoingKeys;
import org.briarproject.bramble.api.transport.TransportKeys;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.util.StringUtils;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Test;
import java.util.ArrayList;
@@ -73,13 +74,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
public class DatabaseComponentImplTest extends BrambleMockTestCase {
@SuppressWarnings("unchecked")
private final Database<Object> database = context.mock(Database.class);
private final ShutdownManager shutdown =
context.mock(ShutdownManager.class);
private final EventBus eventBus = context.mock(EventBus.class);
public class DatabaseComponentImplTest extends BrambleTestCase {
private final Object txn = new Object();
private final ClientId clientId;
@@ -130,8 +125,13 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
}
@Test
@SuppressWarnings("unchecked")
public void testSimpleCalls() throws Exception {
int shutdownHandle = 12345;
Mockery context = new Mockery();
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// open()
oneOf(database).open();
@@ -194,6 +194,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
// endTransaction()
oneOf(database).commitTransaction(txn);
// close()
oneOf(shutdown).removeShutdownHook(shutdownHandle);
oneOf(database).close();
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
@@ -220,11 +221,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.endTransaction(transaction);
}
db.close();
context.assertIsSatisfied();
}
@Test
public void testLocalMessagesAreNotStoredUnlessGroupExists()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -244,10 +252,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testAddLocalMessage() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -279,11 +294,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testVariousMethodsThrowExceptionIfContactIsMissing()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// Check whether the contact is in the DB (which it's not)
exactly(18).of(database).startTransaction();
@@ -478,11 +500,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testVariousMethodsThrowExceptionIfLocalAuthorIsMissing()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// Check whether the pseudonym is in the DB (which it's not)
exactly(3).of(database).startTransaction();
@@ -523,11 +552,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testVariousMethodsThrowExceptionIfGroupIsMissing()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// Check whether the group is in the DB (which it's not)
exactly(8).of(database).startTransaction();
@@ -621,11 +657,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testVariousMethodsThrowExceptionIfMessageIsMissing()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// Check whether the message is in the DB (which it's not)
exactly(11).of(database).startTransaction();
@@ -749,11 +792,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testVariousMethodsThrowExceptionIfTransportIsMissing()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// startTransaction()
oneOf(database).startTransaction();
@@ -840,12 +890,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testGenerateAck() throws Exception {
Collection<MessageId> messagesToAck = Arrays.asList(messageId,
messageId1);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -868,6 +925,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
@@ -875,6 +934,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -905,12 +969,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testGenerateOffer() throws Exception {
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -936,12 +1007,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testGenerateRequest() throws Exception {
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -964,6 +1042,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
@@ -971,6 +1051,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
byte[] raw1 = new byte[size];
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
Collection<byte[]> messages = Arrays.asList(raw, raw1);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1002,10 +1087,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testReceiveAck() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1028,10 +1120,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testReceiveMessage() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1076,10 +1175,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testReceiveDuplicateMessage() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1106,10 +1212,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testReceiveMessageWithoutVisibleGroup() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1129,6 +1242,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
@@ -1136,6 +1251,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
MessageId messageId3 = new MessageId(TestUtils.getRandomId());
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1176,10 +1296,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testReceiveRequest() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1203,10 +1330,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testChangingVisibilityCallsListeners() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1236,11 +1370,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testNotChangingVisibilityDoesNotCallListeners()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1262,6 +1403,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
@@ -1269,6 +1412,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
TransportKeys transportKeys = createTransportKeys();
Map<ContactId, TransportKeys> keys = Collections.singletonMap(
contactId, transportKeys);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// startTransaction()
oneOf(database).startTransaction();
@@ -1298,6 +1446,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
private TransportKeys createTransportKeys() {
@@ -1330,6 +1480,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
Settings merged = new Settings();
merged.put("foo", "bar");
merged.put("baz", "qux");
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
// startTransaction()
oneOf(database).startTransaction();
@@ -1359,6 +1514,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test(expected = IllegalStateException.class)
@@ -1388,6 +1545,12 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
private void testCannotStartTransactionDuringTransaction(
boolean firstTxnReadOnly, boolean secondTxnReadOnly)
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1397,12 +1560,22 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
shutdown);
assertNotNull(db.startTransaction(firstTxnReadOnly));
db.startTransaction(secondTxnReadOnly);
fail();
try {
db.startTransaction(secondTxnReadOnly);
fail();
} finally {
context.assertIsSatisfied();
}
}
@Test
public void testCannotAddLocalIdentityAsContact() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1426,10 +1599,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
public void testCannotAddDuplicateContact() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
@@ -1455,12 +1636,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
} finally {
db.endTransaction(transaction);
}
context.assertIsSatisfied();
}
@Test
@SuppressWarnings("unchecked")
public void testMessageDependencies() throws Exception {
int shutdownHandle = 12345;
Mockery context = new Mockery();
Database<Object> database = context.mock(Database.class);
ShutdownManager shutdown = context.mock(ShutdownManager.class);
EventBus eventBus = context.mock(EventBus.class);
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
context.checking(new Expectations() {{
// open()
@@ -1506,6 +1693,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
// endTransaction()
oneOf(database).commitTransaction(txn);
// close()
oneOf(shutdown).removeShutdownHook(shutdownHandle);
oneOf(database).close();
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
@@ -1526,5 +1714,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.endTransaction(transaction);
}
db.close();
context.assertIsSatisfied();
}
}

View File

@@ -150,17 +150,14 @@ public class LanTcpPluginTest extends BrambleTestCase {
int port = ss.getLocalPort();
CountDownLatch latch = new CountDownLatch(1);
AtomicBoolean error = new AtomicBoolean(false);
new Thread() {
@Override
public void run() {
try {
ss.accept();
latch.countDown();
} catch (IOException e) {
error.set(true);
}
new Thread(() -> {
try {
ss.accept();
latch.countDown();
} catch (IOException e) {
error.set(true);
}
}.start();
}).start();
// Tell the plugin about the port
TransportProperties p = new TransportProperties();
p.put("ipPorts", addrString + ":" + port);
@@ -243,17 +240,14 @@ public class LanTcpPluginTest extends BrambleTestCase {
ss.bind(new InetSocketAddress(addrString, 0), 10);
CountDownLatch latch = new CountDownLatch(1);
AtomicBoolean error = new AtomicBoolean(false);
new Thread() {
@Override
public void run() {
try {
ss.accept();
latch.countDown();
} catch (IOException e) {
error.set(true);
}
new Thread(() -> {
try {
ss.accept();
latch.countDown();
} catch (IOException e) {
error.set(true);
}
}.start();
}).start();
// Tell the plugin about the port
BdfList descriptor = new BdfList();
descriptor.add(TRANSPORT_ID_LAN);

View File

@@ -215,6 +215,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Metadata meta = new Metadata();
// Version 4 is being delivered
BdfDictionary metaDictionary = BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 4),
@@ -222,19 +223,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
);
Map<MessageId, BdfDictionary> messageMetadata =
new LinkedHashMap<>();
// Old remote updates for the same transport should be deleted
MessageId fooVersion2 = new MessageId(getRandomId());
messageMetadata.put(fooVersion2, BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 2),
new BdfEntry("local", false)
));
MessageId fooVersion1 = new MessageId(getRandomId());
messageMetadata.put(fooVersion1, BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 1),
new BdfEntry("local", false)
));
// An older remote update for the same transport should be deleted
MessageId fooVersion3 = new MessageId(getRandomId());
messageMetadata.put(fooVersion3, BdfDictionary.of(
new BdfEntry("transportId", "foo"),
@@ -248,11 +237,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroupId);
will(returnValue(messageMetadata));
// Versions 1-3 should be deleted
oneOf(db).deleteMessage(txn, fooVersion1);
oneOf(db).deleteMessageMetadata(txn, fooVersion1);
oneOf(db).deleteMessage(txn, fooVersion2);
oneOf(db).deleteMessageMetadata(txn, fooVersion2);
// The previous update (version 3) should be deleted
oneOf(db).deleteMessage(txn, fooVersion3);
oneOf(db).deleteMessageMetadata(txn, fooVersion3);
}});
@@ -268,6 +253,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
long timestamp = 123456789;
Message message = getMessage(contactGroupId, timestamp);
Metadata meta = new Metadata();
// Version 3 is being delivered
BdfDictionary metaDictionary = BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 3),
@@ -275,19 +261,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
);
Map<MessageId, BdfDictionary> messageMetadata =
new LinkedHashMap<>();
// Old remote updates for the same transport should be deleted
MessageId fooVersion2 = new MessageId(getRandomId());
messageMetadata.put(fooVersion2, BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 2),
new BdfEntry("local", false)
));
MessageId fooVersion1 = new MessageId(getRandomId());
messageMetadata.put(fooVersion1, BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 1),
new BdfEntry("local", false)
));
// A newer remote update for the same transport should not be deleted
MessageId fooVersion4 = new MessageId(getRandomId());
messageMetadata.put(fooVersion4, BdfDictionary.of(
@@ -302,11 +275,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroupId);
will(returnValue(messageMetadata));
// Versions 1 and 2 should be deleted, version 4 should not
oneOf(db).deleteMessage(txn, fooVersion1);
oneOf(db).deleteMessageMetadata(txn, fooVersion1);
oneOf(db).deleteMessage(txn, fooVersion2);
oneOf(db).deleteMessageMetadata(txn, fooVersion2);
// The update being delivered (version 3) should be deleted
oneOf(db).deleteMessage(txn, message.getId());
oneOf(db).deleteMessageMetadata(txn, message.getId());
@@ -343,7 +311,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
@Test
public void testReturnsLatestLocalProperties() throws Exception {
Transaction txn = new Transaction(null, false);
Transaction txn = new Transaction(null, true);
expectGetLocalProperties(txn);
@@ -357,7 +325,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
@Test
public void testReturnsEmptyPropertiesIfNoLocalPropertiesAreFound()
throws Exception {
Transaction txn = new Transaction(null, false);
Transaction txn = new Transaction(null, true);
Map<MessageId, BdfDictionary> messageMetadata =
new LinkedHashMap<>();
// A local update for another transport should be ignored
@@ -369,7 +337,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
));
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
@@ -384,7 +352,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
@Test
public void testReturnsLocalProperties() throws Exception {
Transaction txn = new Transaction(null, false);
Transaction txn = new Transaction(null, true);
Map<MessageId, BdfDictionary> messageMetadata =
new LinkedHashMap<>();
// A local update for another transport should be ignored
@@ -404,7 +372,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
@@ -423,7 +391,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
@Test
public void testReturnsRemotePropertiesOrEmptyProperties()
throws Exception {
Transaction txn = new Transaction(null, false);
Transaction txn = new Transaction(null, true);
Contact contact1 = getContact(false);
Contact contact2 = getContact(true);
Contact contact3 = getContact(true);
@@ -457,7 +425,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).getContacts(txn);
will(returnValue(contacts));
@@ -638,28 +606,14 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
return new Message(messageId, g, timestamp, raw);
}
private void expectGetLocalProperties(Transaction txn)
throws Exception {
Map<MessageId, BdfDictionary> messageMetadata =
new LinkedHashMap<>();
// The only update for transport "foo" should be returned
private void expectGetLocalProperties(Transaction txn) throws Exception {
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
// The latest update for transport "foo" should be returned
MessageId fooVersion999 = new MessageId(getRandomId());
messageMetadata.put(fooVersion999, BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 999)
));
// An old update for transport "bar" should be deleted
MessageId barVersion2 = new MessageId(getRandomId());
messageMetadata.put(barVersion2, BdfDictionary.of(
new BdfEntry("transportId", "bar"),
new BdfEntry("version", 2)
));
// An even older update for transport "bar" should be deleted
MessageId barVersion1 = new MessageId(getRandomId());
messageMetadata.put(barVersion1, BdfDictionary.of(
new BdfEntry("transportId", "bar"),
new BdfEntry("version", 1)
));
// The latest update for transport "bar" should be returned
MessageId barVersion3 = new MessageId(getRandomId());
messageMetadata.put(barVersion3, BdfDictionary.of(
@@ -674,8 +628,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(messageMetadata));
oneOf(db).removeMessage(txn, barVersion1);
oneOf(db).removeMessage(txn, barVersion2);
// Retrieve and parse the latest local properties
oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
will(returnValue(fooUpdate));

View File

@@ -12,16 +12,16 @@ dependencies {
implementation 'net.java.dev.jna:jna:4.4.0'
implementation 'net.java.dev.jna:jna-platform:4.4.0'
apt 'com.google.dagger:dagger-compiler:2.0.2'
apt "com.google.dagger:dagger-compiler:$daggerVersion"
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.jmock:jmock:$jmockVersion"
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
}
dependencyVerification {
@@ -36,6 +36,7 @@ dependencyVerification {
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'net.java.dev.jna:jna-platform:4.4.0:jna-platform-4.4.0.jar:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
'net.java.dev.jna:jna:4.4.0:jna-4.4.0.jar:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',

View File

@@ -6,7 +6,6 @@ dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation project(path: ':bramble-android', configuration: 'default')
def supportVersion = '27.0.1'
implementation "com.android.support:support-v4:$supportVersion"
implementation("com.android.support:appcompat-v7:$supportVersion") {
exclude module: 'support-v4'
@@ -20,7 +19,7 @@ dependencies {
}
implementation "com.android.support:cardview-v7:$supportVersion"
implementation "com.android.support:support-annotations:$supportVersion"
implementation 'com.android.support.constraint:constraint-layout:1.1.0-beta3'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation('ch.acra:acra:4.8.5') {
exclude module: 'support-v4'
@@ -34,7 +33,7 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:3.8.0'
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.1.0'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
compileOnly 'javax.annotation:jsr250-api:1.0'
@@ -43,12 +42,12 @@ dependencies {
testImplementation 'org.robolectric:robolectric:3.5.1'
testImplementation 'org.robolectric:shadows-support-v4:3.0'
testImplementation 'org.mockito:mockito-core:2.8.9'
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.jmock:jmock:$jmockVersion"
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
}
dependencyVerification {
@@ -61,8 +60,8 @@ dependencyVerification {
'ch.acra:acra:4.8.5:acra-4.8.5.aar:afd5b28934d5166b55f261c85685ad59e8a4ebe9ca1960906afaa8c76d8dc9eb',
'classworlds:classworlds:1.1-alpha-2:classworlds-1.1-alpha-2.jar:2bf4e59f3acd106fea6145a9a88fe8956509f8b9c0fdd11eb96fee757269e3f3',
'com.almworks.sqlite4java:sqlite4java:0.282:sqlite4java-0.282.jar:9e1d8dd83ca6003f841e3af878ce2dc7c22497493a7bb6d1b62ec1b0d0a83c05',
'com.android.support.constraint:constraint-layout-solver:1.1.0-beta3:constraint-layout-solver-1.1.0-beta3.jar:c9084108415046c423983bdff8cf04c8e9a5bed41b8d5329f3764c08312ee3dd',
'com.android.support.constraint:constraint-layout:1.1.0-beta3:constraint-layout-1.1.0-beta3.aar:1754a6bd135feae485aa2ebf9e170f0f3d3282b392f8aa3067d0ed668839db79',
'com.android.support.constraint:constraint-layout-solver:1.0.2:constraint-layout-solver-1.0.2.jar:8c62525a9bc5cff5633a96cb9b32fffeccaf41b8841aa87fc22607070dea9b8d',
'com.android.support.constraint:constraint-layout:1.0.2:constraint-layout-1.0.2.aar:b0c688cc2b7172608f8153a689d746da40f71e52d7e2fe2bfd9df2f92db77085',
'com.android.support:animated-vector-drawable:27.0.1:animated-vector-drawable-27.0.1.aar:365050110411c86c7eec86101b49ab53557ffe6667f60b19055f1d35c38a577b',
'com.android.support:appcompat-v7:27.0.1:appcompat-v7-27.0.1.aar:1402c29a49db30346c21a7d40634461765b3ab826f5dd95bc4dcc76787b21851',
'com.android.support:cardview-v7:27.0.1:cardview-v7-27.0.1.aar:43fccd44086c51eaa9d78be2fcf0dfea1556c8876a6fd325ea8d24e860054202',
@@ -108,6 +107,7 @@ dependencyVerification {
'nekohtml:xercesMinimal:1.9.6.2:xercesMinimal-1.9.6.2.jar:95b8b357d19f63797dd7d67622fd3f18374d64acbc6584faba1c7759a31e8438',
'net.bytebuddy:byte-buddy-agent:1.6.14:byte-buddy-agent-1.6.14.jar:c141a2d6809c3eeff4a43d25992826abccebdd4b793af3e7a5f346e88ae73a33',
'net.bytebuddy:byte-buddy:1.6.14:byte-buddy-1.6.14.jar:917758b3c651e278a15a029ba1d42dbf802d8b0e1fe2aa4b81c5750c64f461c1',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.apache.maven.wagon:wagon-file:1.0-beta-6:wagon-file-1.0-beta-6.jar:7298feeb36ff14dd933c38e62585fb9973fea32fb3c4bc5379428cb1aac5dd3c',
@@ -185,19 +185,19 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 1615
versionName "0.16.15"
applicationId "org.briarproject.briar.beta"
resValue "string", "app_package", "org.briarproject.briar.beta"
resValue "string", "app_name", "Briar Beta"
versionCode 1700
versionName "0.17.0"
applicationId "org.briarproject.briar.android"
resValue "string", "app_package", "org.briarproject.briar.android"
resValue "string", "app_name", "Briar"
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
}
buildTypes {
debug {
applicationIdSuffix ".debug"
resValue "string", "app_package", "org.briarproject.briar.beta.debug"
resValue "string", "app_name", "Briar Beta Debug"
resValue "string", "app_package", "org.briarproject.briar.android.debug"
resValue "string", "app_name", "Briar Debug"
shrinkResources false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'

View File

@@ -1,14 +1,11 @@
package org.briarproject.briar.android;
import android.annotation.TargetApi;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.support.v4.app.TaskStackBuilder;
@@ -47,7 +44,6 @@ import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
@@ -61,10 +57,8 @@ import javax.inject.Inject;
import static android.app.Notification.DEFAULT_LIGHTS;
import static android.app.Notification.DEFAULT_SOUND;
import static android.app.Notification.DEFAULT_VIBRATE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.os.Build.VERSION.SDK_INT;
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
import static java.util.logging.Level.WARNING;
@@ -89,12 +83,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
private static final int BLOG_POST_NOTIFICATION_ID = 6;
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 7;
// Channel IDs
private static final String CONTACT_CHANNEL_ID = "contacts";
private static final String GROUP_CHANNEL_ID = "groups";
private static final String FORUM_CHANNEL_ID = "forums";
private static final String BLOG_CHANNEL_ID = "blogs";
private static final long SOUND_DELAY = TimeUnit.SECONDS.toMillis(2);
private static final Logger LOG =
@@ -103,9 +91,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
private final Executor dbExecutor;
private final SettingsManager settingsManager;
private final AndroidExecutor androidExecutor;
private final Clock clock;
private final Context appContext;
private final NotificationManager notificationManager;
private final Clock clock;
private final AtomicBoolean used = new AtomicBoolean(false);
// The following must only be accessed on the main UI thread
@@ -134,8 +121,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
this.androidExecutor = androidExecutor;
this.clock = clock;
appContext = app.getApplicationContext();
notificationManager = (NotificationManager)
appContext.getSystemService(NOTIFICATION_SERVICE);
}
@Override
@@ -147,33 +132,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
} catch (DbException e) {
throw new ServiceException(e);
}
if (SDK_INT >= 26) {
// Create notification channels
Callable<Void> task = () -> {
createNotificationChannel(CONTACT_CHANNEL_ID,
R.string.contact_list_button);
createNotificationChannel(GROUP_CHANNEL_ID,
R.string.groups_button);
createNotificationChannel(FORUM_CHANNEL_ID,
R.string.forums_button);
createNotificationChannel(BLOG_CHANNEL_ID,
R.string.blogs_button);
return null;
};
try {
androidExecutor.runOnUiThread(task).get();
} catch (InterruptedException | ExecutionException e) {
throw new ServiceException(e);
}
}
}
@TargetApi(26)
private void createNotificationChannel(String channelId,
@StringRes int name) {
notificationManager.createNotificationChannel(
new NotificationChannel(channelId, appContext.getString(name),
IMPORTANCE_DEFAULT));
}
@Override
@@ -198,34 +156,44 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
private void clearContactNotification() {
contactCounts.clear();
contactTotal = 0;
notificationManager.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID);
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID);
}
@UiThread
private void clearGroupMessageNotification() {
groupCounts.clear();
groupTotal = 0;
notificationManager.cancel(GROUP_MESSAGE_NOTIFICATION_ID);
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.cancel(GROUP_MESSAGE_NOTIFICATION_ID);
}
@UiThread
private void clearForumPostNotification() {
forumCounts.clear();
forumTotal = 0;
notificationManager.cancel(FORUM_POST_NOTIFICATION_ID);
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.cancel(FORUM_POST_NOTIFICATION_ID);
}
@UiThread
private void clearBlogPostNotification() {
blogCounts.clear();
blogTotal = 0;
notificationManager.cancel(BLOG_POST_NOTIFICATION_ID);
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.cancel(BLOG_POST_NOTIFICATION_ID);
}
@UiThread
private void clearIntroductionSuccessNotification() {
introductionTotal = 0;
notificationManager.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
}
@Override
@@ -301,8 +269,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
if (contactTotal == 0) {
clearContactNotification();
} else if (settings.getBoolean(PREF_NOTIFY_PRIVATE, true)) {
BriarNotificationBuilder b = new BriarNotificationBuilder(
appContext, CONTACT_CHANNEL_ID);
BriarNotificationBuilder b =
new BriarNotificationBuilder(appContext);
b.setSmallIcon(R.drawable.notification_private_message);
b.setColorRes(R.color.briar_primary);
b.setContentTitle(appContext.getText(R.string.app_name));
@@ -337,8 +305,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
t.addNextIntent(i);
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
}
notificationManager.notify(PRIVATE_MESSAGE_NOTIFICATION_ID,
b.build());
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build());
}
}
@@ -409,7 +378,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
clearGroupMessageNotification();
} else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) {
BriarNotificationBuilder b =
new BriarNotificationBuilder(appContext, GROUP_CHANNEL_ID);
new BriarNotificationBuilder(appContext);
b.setSmallIcon(R.drawable.notification_private_group);
b.setColorRes(R.color.briar_primary);
b.setContentTitle(appContext.getText(R.string.app_name));
@@ -445,8 +414,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
t.addNextIntent(i);
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
}
notificationManager.notify(GROUP_MESSAGE_NOTIFICATION_ID,
b.build());
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.notify(GROUP_MESSAGE_NOTIFICATION_ID, b.build());
}
}
@@ -485,7 +455,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
clearForumPostNotification();
} else if (settings.getBoolean(PREF_NOTIFY_FORUM, true)) {
BriarNotificationBuilder b =
new BriarNotificationBuilder(appContext, FORUM_CHANNEL_ID);
new BriarNotificationBuilder(appContext);
b.setSmallIcon(R.drawable.notification_forum);
b.setColorRes(R.color.briar_primary);
b.setContentTitle(appContext.getText(R.string.app_name));
@@ -521,7 +491,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
t.addNextIntent(i);
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
}
notificationManager.notify(FORUM_POST_NOTIFICATION_ID, b.build());
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.notify(FORUM_POST_NOTIFICATION_ID, b.build());
}
}
@@ -560,7 +532,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
clearBlogPostNotification();
} else if (settings.getBoolean(PREF_NOTIFY_BLOG, true)) {
BriarNotificationBuilder b =
new BriarNotificationBuilder(appContext, BLOG_CHANNEL_ID);
new BriarNotificationBuilder(appContext);
b.setSmallIcon(R.drawable.notification_blog);
b.setColorRes(R.color.briar_primary);
b.setContentTitle(appContext.getText(R.string.app_name));
@@ -583,7 +555,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
t.addNextIntent(i);
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
notificationManager.notify(BLOG_POST_NOTIFICATION_ID, b.build());
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.notify(BLOG_POST_NOTIFICATION_ID, b.build());
}
}
@@ -603,8 +577,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
@UiThread
private void updateIntroductionNotification() {
BriarNotificationBuilder b =
new BriarNotificationBuilder(appContext, CONTACT_CHANNEL_ID);
BriarNotificationBuilder b = new BriarNotificationBuilder(appContext);
b.setSmallIcon(R.drawable.notification_introduction);
b.setColorRes(R.color.briar_primary);
b.setContentTitle(appContext.getText(R.string.app_name));
@@ -626,8 +599,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
t.addNextIntent(i);
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
notificationManager.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID,
b.build());
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
NotificationManager nm = (NotificationManager) o;
nm.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID, b.build());
}
@Override

View File

@@ -6,8 +6,8 @@ package org.briarproject.briar.android;
*/
public interface BriarApplication {
// This build expires on 31 December 2017
long EXPIRY_DATE = 1514761200 * 1000L;
// This build expires on 31 December 2018
long EXPIRY_DATE = 1546214400 * 1000L;
AndroidComponent getApplicationComponent();

View File

@@ -8,6 +8,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
@@ -25,12 +26,9 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Build.VERSION.SDK_INT;
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
@@ -40,21 +38,9 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResul
public class BriarService extends Service {
public static String EXTRA_START_RESULT =
"org.briarproject.briar.START_RESULT";
public static String EXTRA_NOTIFICATION_ID =
"org.briarproject.briar.FAILURE_NOTIFICATION_ID";
public static String EXTRA_STARTUP_FAILED =
"org.briarproject.briar.STARTUP_FAILED";
private static final int ONGOING_NOTIFICATION_ID = 1;
private static final int FAILURE_NOTIFICATION_ID = 2;
// Channels are sorted by channel ID in the Settings app, so use IDs
// that will sort below the main channels such as contacts
private static final String ONGOING_CHANNEL_ID = "zForegroundService";
private static final String FAILURE_CHANNEL_ID = "zStartupFailure";
private static final Logger LOG =
Logger.getLogger(BriarService.class.getName());
@@ -88,26 +74,20 @@ public class BriarService extends Service {
stopSelf();
return;
}
// Create notification channels
if (SDK_INT >= 26) {
NotificationManager nm = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
NotificationChannel ongoingChannel = new NotificationChannel(
ONGOING_CHANNEL_ID,
getString(R.string.ongoing_notification_title),
IMPORTANCE_NONE);
ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET);
nm.createNotificationChannel(ongoingChannel);
NotificationChannel failureChannel = new NotificationChannel(
FAILURE_CHANNEL_ID,
getString(R.string.startup_failed_notification_title),
IMPORTANCE_DEFAULT);
failureChannel.setLockscreenVisibility(VISIBILITY_SECRET);
nm.createNotificationChannel(failureChannel);
// Create mandatory notification channel
String channelId = "foregroundService";
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(channelId,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_NONE);
channel.setLockscreenVisibility(VISIBILITY_SECRET);
NotificationManager nm =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.createNotificationChannel(channel);
}
// Show an ongoing notification that the service is running
NotificationCompat.Builder b =
new NotificationCompat.Builder(this, ONGOING_CHANNEL_ID);
new NotificationCompat.Builder(this, channelId);
b.setSmallIcon(R.drawable.notification_ongoing);
b.setColor(ContextCompat.getColor(this, R.color.briar_primary));
b.setContentTitle(getText(R.string.ongoing_notification_title));
@@ -117,37 +97,34 @@ public class BriarService extends Service {
Intent i = new Intent(this, NavDrawerActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
if (SDK_INT >= 21) {
if (Build.VERSION.SDK_INT >= 21) {
b.setCategory(CATEGORY_SERVICE);
b.setVisibility(VISIBILITY_SECRET);
}
b.setPriority(PRIORITY_MIN);
startForeground(ONGOING_NOTIFICATION_ID, b.build());
// Start the services in a background thread
new Thread() {
@Override
public void run() {
String nickname = databaseConfig.getLocalAuthorName();
StartResult result = lifecycleManager.startServices(nickname);
if (result == SUCCESS) {
started = true;
} else if (result == ALREADY_RUNNING) {
LOG.info("Already running");
stopSelf();
} else {
if (LOG.isLoggable(WARNING))
LOG.warning("Startup failed: " + result);
showStartupFailureNotification(result);
stopSelf();
}
new Thread(() -> {
String nickname = databaseConfig.getLocalAuthorName();
StartResult result = lifecycleManager.startServices(nickname);
if (result == SUCCESS) {
started = true;
} else if (result == ALREADY_RUNNING) {
LOG.info("Already running");
stopSelf();
} else {
if (LOG.isLoggable(WARNING))
LOG.warning("Startup failed: " + result);
showStartupFailureNotification(result);
stopSelf();
}
}.start();
}).start();
}
private void showStartupFailureNotification(StartResult result) {
androidExecutor.runOnUiThread(() -> {
NotificationCompat.Builder b = new NotificationCompat.Builder(
BriarService.this, FAILURE_CHANNEL_ID);
NotificationCompat.Builder b =
new NotificationCompat.Builder(BriarService.this);
b.setSmallIcon(android.R.drawable.stat_notify_error);
b.setContentTitle(getText(
R.string.startup_failed_notification_title));
@@ -156,8 +133,9 @@ public class BriarService extends Service {
Intent i = new Intent(BriarService.this,
StartupFailureActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
i.putExtra(EXTRA_START_RESULT, result);
i.putExtra(EXTRA_NOTIFICATION_ID, FAILURE_NOTIFICATION_ID);
i.putExtra("briar.START_RESULT", result);
i.putExtra("briar.FAILURE_NOTIFICATION_ID",
FAILURE_NOTIFICATION_ID);
b.setContentIntent(PendingIntent.getActivity(BriarService.this,
0, i, FLAG_UPDATE_CURRENT));
Object o = getSystemService(NOTIFICATION_SERVICE);
@@ -166,7 +144,7 @@ public class BriarService extends Service {
// Bring the dashboard to the front to clear the back stack
i = new Intent(BriarService.this, NavDrawerActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
i.putExtra(EXTRA_STARTUP_FAILED, true);
i.putExtra("briar.STARTUP_FAILED", true);
startActivity(i);
});
}
@@ -187,12 +165,9 @@ public class BriarService extends Service {
LOG.info("Destroyed");
stopForeground(true);
// Stop the services in a background thread
new Thread() {
@Override
public void run() {
if (started) lifecycleManager.stopServices();
}
}.start();
new Thread(() -> {
if (started) lifecycleManager.stopServices();
}).start();
}
@Override

View File

@@ -10,8 +10,6 @@ import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
import static org.briarproject.briar.android.BriarService.EXTRA_NOTIFICATION_ID;
import static org.briarproject.briar.android.BriarService.EXTRA_START_RESULT;
public class StartupFailureActivity extends BaseActivity {
@@ -29,9 +27,8 @@ public class StartupFailureActivity extends BaseActivity {
}
private void handleIntent(Intent i) {
StartResult result =
(StartResult) i.getSerializableExtra(EXTRA_START_RESULT);
int notificationId = i.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
StartResult result = (StartResult) i.getSerializableExtra("briar.START_RESULT");
int notificationId = i.getIntExtra("briar.FAILURE_NOTIFICATION_ID", -1);
// cancel notification
if (notificationId > -1) {

View File

@@ -18,7 +18,7 @@ public interface TestingConstants {
* Whether this is a beta build. This should be set to false for final
* release builds.
*/
boolean IS_BETA_BUILD = true;
boolean IS_BETA_BUILD = false;
/**
* Default log level. Disable logging for final release builds.

View File

@@ -4,7 +4,6 @@ import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.LayoutRes;
import android.support.annotation.UiThread;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
@@ -139,9 +138,7 @@ public abstract class BaseActivity extends AppCompatActivity
dialogFrag =
ScreenFilterDialogFragment.newInstance(new ArrayList<>(apps));
dialogFrag.setCancelable(false);
// Show dialog unless onSaveInstanceState() has been called, see #1112
FragmentManager fm = getSupportFragmentManager();
if (!fm.isStateSaved()) dialogFrag.show(fm, dialogFrag.getTag());
dialogFrag.show(getSupportFragmentManager(), dialogFrag.getTag());
}
@Override

View File

@@ -27,7 +27,6 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
import static android.os.Build.MANUFACTURER;
import static android.os.Build.VERSION.SDK_INT;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
@@ -36,6 +35,7 @@ import static org.briarproject.briar.android.util.UiUtils.getDozeWhitelistingInt
@SuppressLint("Registered")
public abstract class BriarActivity extends BaseActivity {
public static final String KEY_STARTUP_FAILED = "briar.STARTUP_FAILED";
public static final String GROUP_ID = "briar.GROUP_ID";
public static final String GROUP_NAME = "briar.GROUP_NAME";
@@ -79,10 +79,6 @@ public abstract class BriarActivity extends BaseActivity {
public void setSceneTransitionAnimation() {
if (SDK_INT < 21) return;
// workaround for #1007
if (SDK_INT == 24 && MANUFACTURER.equalsIgnoreCase("Samsung")) {
return;
}
Transition slide = new Slide(Gravity.RIGHT);
slide.excludeTarget(android.R.id.statusBarBackground, true);
slide.excludeTarget(android.R.id.navigationBarBackground, true);
@@ -130,8 +126,8 @@ public abstract class BriarActivity extends BaseActivity {
b.setNegativeButton(R.string.cancel,
(dialog, which) -> dialog.dismiss());
b.setOnDismissListener(dialog -> {
CheckBox checkBox =
((AlertDialog) dialog).findViewById(R.id.checkbox);
CheckBox checkBox = (CheckBox) ((AlertDialog) dialog)
.findViewById(R.id.checkbox);
if (checkBox.isChecked())
briarController.doNotAskAgainForDozeWhiteListing();
});

View File

@@ -123,25 +123,22 @@ public class BriarControllerImpl implements BriarController {
@Override
public void signOut(ResultHandler<Void> eventHandler) {
new Thread() {
@Override
public void run() {
try {
// Wait for the service to finish starting up
IBinder binder = serviceConnection.waitForBinder();
BriarService service =
((BriarService.BriarBinder) binder).getService();
service.waitForStartup();
// Shut down the service and wait for it to shut down
LOG.info("Shutting down service");
service.shutdown();
service.waitForShutdown();
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for service");
}
eventHandler.onResult(null);
new Thread(() -> {
try {
// Wait for the service to finish starting up
IBinder binder = serviceConnection.waitForBinder();
BriarService service =
((BriarService.BriarBinder) binder).getService();
service.waitForStartup();
// Shut down the service and wait for it to shut down
LOG.info("Shutting down service");
service.shutdown();
service.waitForShutdown();
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for service");
}
}.start();
eventHandler.onResult(null);
}).start();
}
private void unbindService() {

View File

@@ -1,19 +1,17 @@
package org.briarproject.briar.android.login;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.login.PowerView.OnCheckedChangedListener;
import org.briarproject.briar.android.util.UiUtils;
import static android.view.View.INVISIBLE;
@@ -21,15 +19,12 @@ import static android.view.View.VISIBLE;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@NotNullByDefault
public class DozeFragment extends SetupFragment
implements OnCheckedChangedListener {
@TargetApi(23)
public class DozeFragment extends SetupFragment {
private final static String TAG = DozeFragment.class.getName();
private DozeView dozeView;
private HuaweiView huaweiView;
private Button next;
private Button dozeButton;
private ProgressBar progressBar;
private boolean secondAttempt = false;
@@ -38,22 +33,15 @@ public class DozeFragment extends SetupFragment
}
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setTitle(getString(R.string.setup_doze_title));
setHasOptionsMenu(false);
View v = inflater.inflate(R.layout.fragment_setup_doze, container,
false);
dozeView = v.findViewById(R.id.dozeView);
dozeView.setOnCheckedChangedListener(this);
huaweiView = v.findViewById(R.id.huaweiView);
huaweiView.setOnCheckedChangedListener(this);
next = v.findViewById(R.id.next);
dozeButton = v.findViewById(R.id.dozeButton);
progressBar = v.findViewById(R.id.progress);
dozeView.setOnButtonClickListener(this::askForDozeWhitelisting);
next.setOnClickListener(this);
dozeButton.setOnClickListener(view -> askForDozeWhitelisting());
return v;
}
@@ -77,34 +65,25 @@ public class DozeFragment extends SetupFragment
public void onActivityResult(int request, int result, Intent data) {
super.onActivityResult(request, result, data);
if (request == REQUEST_DOZE_WHITELISTING) {
if (!dozeView.needsToBeShown() || secondAttempt) {
dozeView.setChecked(true);
} else if (getContext() != null) {
if (!setupController.needsDozeWhitelisting() || secondAttempt) {
dozeButton.setEnabled(false);
onClick(dozeButton);
} else {
secondAttempt = true;
showOnboardingDialog(getContext(), getHelpText());
}
}
}
@Override
public void onCheckedChanged() {
if (dozeView.isChecked() && huaweiView.isChecked()) {
next.setEnabled(true);
} else {
next.setEnabled(false);
}
}
@SuppressLint("BatteryLife")
private void askForDozeWhitelisting() {
if (getContext() == null) return;
Intent i = UiUtils.getDozeWhitelistingIntent(getContext());
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
}
@Override
public void onClick(View view) {
next.setVisibility(INVISIBLE);
dozeButton.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE);
setupController.createAccount();
}

View File

@@ -1,60 +0,0 @@
package org.briarproject.briar.android.login;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.util.AttributeSet;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
@UiThread
@NotNullByDefault
class DozeView extends PowerView {
@Nullable
private Runnable onButtonClickListener;
public DozeView(Context context) {
this(context, null);
}
public DozeView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DozeView(Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
setText(R.string.setup_doze_intro);
setButtonText(R.string.setup_doze_button);
}
@Override
public boolean needsToBeShown() {
return needsToBeShown(getContext());
}
public static boolean needsToBeShown(Context context) {
return needsDozeWhitelisting(context);
}
@Override
protected int getHelpText() {
return R.string.setup_doze_explanation;
}
@Override
protected void onButtonClick() {
if (onButtonClickListener == null) throw new IllegalStateException();
onButtonClickListener.run();
}
public void setOnButtonClickListener(Runnable runnable) {
onButtonClickListener = runnable;
}
}

View File

@@ -1,72 +0,0 @@
package org.briarproject.briar.android.login;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.util.AttributeSet;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import java.util.List;
import javax.annotation.Nullable;
@UiThread
@NotNullByDefault
class HuaweiView extends PowerView {
private final static String PACKAGE_NAME = "com.huawei.systemmanager";
private final static String CLASS_NAME =
PACKAGE_NAME + ".optimize.process.ProtectActivity";
public HuaweiView(Context context) {
this(context, null);
}
public HuaweiView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public HuaweiView(Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
setText(R.string.setup_huawei_text);
setButtonText(R.string.setup_huawei_button);
}
@Override
public boolean needsToBeShown() {
return needsToBeShown(getContext());
}
public static boolean needsToBeShown(Context context) {
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(getIntent(),
PackageManager.MATCH_DEFAULT_ONLY);
return !resolveInfos.isEmpty();
}
@Override
@StringRes
protected int getHelpText() {
return R.string.setup_huawei_help;
}
@Override
protected void onButtonClick() {
getContext().startActivity(getIntent());
setChecked(true);
}
private static Intent getIntent() {
Intent intent = new Intent();
intent.setClassName(PACKAGE_NAME, CLASS_NAME);
return intent;
}
}

View File

@@ -66,7 +66,7 @@ public class PasswordFragment extends SetupFragment {
component.inject(this);
// the controller is not yet available in onCreateView()
if (!setupController.needToShowDozeFragment()) {
if (!setupController.needsDozeWhitelisting()) {
nextButton.setText(R.string.create_account_button);
}
}
@@ -102,7 +102,7 @@ public class PasswordFragment extends SetupFragment {
@Override
public void onClick(View view) {
if (!setupController.needToShowDozeFragment()) {
if (!setupController.needsDozeWhitelisting()) {
nextButton.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE);
}

View File

@@ -1,162 +0,0 @@
package org.briarproject.briar.android.login;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.support.constraint.ConstraintLayout;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.R;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@UiThread
@NotNullByDefault
abstract class PowerView extends ConstraintLayout {
private final TextView textView;
private final ImageView checkImage;
private final Button button;
private boolean checked = false;
@Nullable
private OnCheckedChangedListener onCheckedChangedListener;
public PowerView(Context context) {
this(context, null);
}
public PowerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
@SuppressWarnings("ConstantConditions")
public PowerView(Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.power_view, this, true);
textView = v.findViewById(R.id.textView);
checkImage = v.findViewById(R.id.checkImage);
button = v.findViewById(R.id.button);
button.setOnClickListener(view -> onButtonClick());
ImageButton helpButton = v.findViewById(R.id.helpButton);
helpButton.setOnClickListener(view -> onHelpButtonClick());
// we need to manage the checkImage state ourselves, because automatic
// state saving is done based on the view's ID and there can be
// multiple ImageViews with the same ID in the view hierarchy
setSaveFromParentEnabled(true);
if (!isInEditMode() && !needsToBeShown()) {
setVisibility(GONE);
}
}
@Nullable
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.value = new boolean[] {checked};
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setChecked(ss.value[0]); // also calls listener
}
public abstract boolean needsToBeShown();
public void setChecked(boolean checked) {
this.checked = checked;
if (checked) {
checkImage.setImageResource(R.drawable.ic_check_white);
} else {
checkImage.setImageResource(R.drawable.contact_disconnected);
}
if (onCheckedChangedListener != null) {
onCheckedChangedListener.onCheckedChanged();
}
}
public boolean isChecked() {
return getVisibility() == GONE || checked;
}
public void setOnCheckedChangedListener(
OnCheckedChangedListener onCheckedChangedListener) {
this.onCheckedChangedListener = onCheckedChangedListener;
}
@StringRes
protected abstract int getHelpText();
protected void setText(@StringRes int res) {
textView.setText(res);
}
protected void setButtonText(@StringRes int res) {
button.setText(res);
}
protected abstract void onButtonClick();
private void onHelpButtonClick() {
showOnboardingDialog(getContext(),
getContext().getString(getHelpText()));
}
private static class SavedState extends BaseSavedState {
private boolean[] value = {false};
private SavedState(@Nullable Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
in.readBooleanArray(value);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeBooleanArray(value);
}
static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
interface OnCheckedChangedListener {
void onCheckedChanged();
}
}

View File

@@ -8,7 +8,7 @@ public interface SetupController {
void setSetupActivity(SetupActivity setupActivity);
boolean needToShowDozeFragment();
boolean needsDozeWhitelisting();
void setAuthorName(String authorName);

View File

@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.controller.handler.ResultHandler;
import org.briarproject.briar.android.controller.handler.UiResultHandler;
import org.briarproject.briar.android.util.UiUtils;
import java.util.concurrent.Executor;
@@ -40,10 +41,9 @@ public class SetupControllerImpl extends PasswordControllerImpl
}
@Override
public boolean needToShowDozeFragment() {
public boolean needsDozeWhitelisting() {
if (setupActivity == null) throw new IllegalStateException();
return DozeView.needsToBeShown(setupActivity) ||
HuaweiView.needsToBeShown(setupActivity);
return UiUtils.needsDozeWhitelisting(setupActivity);
}
@Override
@@ -61,7 +61,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
@Override
public void showDozeOrCreateAccount() {
if (setupActivity == null) throw new IllegalStateException();
if (needToShowDozeFragment()) {
if (needsDozeWhitelisting()) {
setupActivity.showDozeFragment();
} else {
createAccount();

View File

@@ -51,7 +51,6 @@ import static android.support.v4.view.GravityCompat.START;
import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.briar.android.BriarService.EXTRA_STARTUP_FAILED;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.NO;
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.UPDATE;
@@ -168,7 +167,7 @@ public class NavDrawerActivity extends BriarActivity implements
}
private void exitIfStartupFailed(Intent intent) {
if (intent.getBooleanExtra(EXTRA_STARTUP_FAILED, false)) {
if (intent.getBooleanExtra(KEY_STARTUP_FAILED, false)) {
finish();
LOG.info("Exiting");
System.exit(0);

View File

@@ -29,6 +29,8 @@ import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
import static org.briarproject.briar.android.TestingConstants.IS_BETA_BUILD;
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
import static org.briarproject.briar.android.controller.BriarControllerImpl.DOZE_ASK_AGAIN;
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.NO;
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.SHOW;
@@ -106,6 +108,10 @@ public class NavDrawerControllerImpl extends DbControllerImpl
@Override
public void showExpiryWarning(ResultHandler<ExpiryWarning> handler) {
if (!IS_DEBUG_BUILD && !IS_BETA_BUILD) {
handler.onResult(NO);
return;
}
runOnDbThread(() -> {
try {
Settings settings =

View File

@@ -12,8 +12,8 @@ import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
public class BriarNotificationBuilder extends NotificationCompat.Builder {
public BriarNotificationBuilder(Context context, String channelId) {
super(context, channelId);
public BriarNotificationBuilder(Context context) {
super(context);
// Auto-cancel does not fire the delete intent, see
// https://issuetracker.google.com/issues/36961721
setAutoCancel(true);

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

View File

@@ -26,7 +26,7 @@
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
app:layout_constraintTop_toBottomOf="parent">
<android.support.design.widget.TextInputEditText
android:id="@+id/nickname_entry"

View File

@@ -2,7 +2,6 @@
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
@@ -17,47 +16,38 @@
android:paddingStart="@dimen/margin_activity_horizontal"
android:paddingTop="@dimen/margin_activity_vertical">
<org.briarproject.briar.android.login.DozeView
android:id="@+id/dozeView"
<TextView
android:id="@+id/setup_explanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="@string/setup_doze_intro"
android:textSize="@dimen/text_size_medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<org.briarproject.briar.android.login.HuaweiView
android:id="@+id/huaweiView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/dozeView"/>
<Button
android:id="@+id/next"
android:id="@+id/dozeButton"
style="@style/BriarButton.Default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/create_account_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/huaweiView"
app:layout_constraintVertical_bias="1.0"
tools:enabled="true"/>
android:layout_marginTop="@dimen/margin_activity_horizontal"
android:text="@string/setup_doze_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/setup_explanation"/>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@+id/next"
app:layout_constraintBottom_toBottomOf="@+id/dozeButton"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/next"/>
app:layout_constraintTop_toTopOf="@+id/dozeButton"/>
</android.support.constraint.ConstraintLayout>

View File

@@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="android.support.constraint.ConstraintLayout">
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textSize="@dimen/text_size_medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/setup_huawei_text"/>
<ImageView
android:id="@+id/checkImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/contact_disconnected"
android:tint="?colorControlNormal"
app:layout_constraintBottom_toBottomOf="@+id/button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/button"
tools:ignore="ContentDescription"/>
<Button
android:id="@+id/button"
style="@style/BriarButton.Default"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toStartOf="@+id/helpButton"
app:layout_constraintStart_toEndOf="@+id/checkImage"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:text="@string/setup_huawei_button"/>
<ImageButton
android:id="@+id/helpButton"
style="@style/BriarButton.Default"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:contentDescription="@string/help"
android:src="@drawable/ic_help_outline_white"
app:layout_constraintBottom_toBottomOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/button"/>
</merge>

View File

@@ -16,7 +16,6 @@
<color name="briar_primary_dark">@color/briar_blue_dark</color>
<color name="briar_accent">@color/briar_blue</color>
<color name="control_normal_light">#757575</color>
<!-- text colors -->
<color name="briar_text_link">#06b9ff</color>

View File

@@ -21,11 +21,6 @@
<string name="more_info">More Information</string>
<string name="don_t_ask_again">Don\'t ask again</string>
<string name="setup_huawei_text">Please tap the button below and make sure Briar is protected in the \"Protected Apps\" screen.</string>
<string name="setup_huawei_button">Protect Briar</string>
<string name="setup_huawei_help">If Briar is not added to the protected apps list, it will be unable to run in the background.</string>
<string name="warning_dozed">%s was unable to run in the background</string>
<!-- Login -->
<string name="enter_password">Enter your password:</string>
<string name="try_again">Wrong password, try again</string>
@@ -39,10 +34,10 @@
<string name="startup_failed_db_error">For some reason, your Briar database is corrupted beyond repair. Your account, your data and all your contacts are lost. Unfortunately, you need to reinstall Briar and set up a new account.</string>
<string name="startup_failed_service_error">Briar was unable to start a required plugin. Reinstalling Briar usually solves this problem. However, please note that you will then lose your account and all data associated with it since Briar is not using central servers to store your data on.</string>
<plurals name="expiry_warning">
<item quantity="one">This is a beta version of Briar. Your account will expire in %d day and cannot be renewed.</item>
<item quantity="other">This is a beta version of Briar. Your account will expire in %d days and cannot be renewed.</item>
<item quantity="one">This is a test version of Briar. Your account will expire in %d day and cannot be renewed.</item>
<item quantity="other">This is a test version of Briar. Your account will expire in %d days and cannot be renewed.</item>
</plurals>
<string name="expiry_update">The beta expiry date has been extended. Your account will now expire in %d days.</string>
<string name="expiry_update">The testing expiry date has been extended. Your account will now expire in %d days.</string>
<string name="expiry_date_reached">This software has expired.\nThank you for testing!</string>
<!-- Navigation Drawer -->
@@ -100,8 +95,8 @@
<string name="ellipsis"></string>
<string name="text_too_long">The entered text is too long</string>
<string name="show_onboarding">Show Help Dialog</string>
<string name="warning_dozed">%s was unable to run in the background</string>
<string name="fix">Fix</string>
<string name="help">Help</string>
<!-- Contacts and Private Conversations-->
<string name="no_contacts">It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future.</string>

View File

@@ -5,7 +5,6 @@
<item name="colorPrimary">@color/briar_primary</item>
<item name="colorPrimaryDark">@color/briar_primary_dark</item>
<item name="colorAccent">@color/briar_accent</item>
<item name="colorControlNormal">@color/control_normal_light</item>
<item name="android:textColorLink">@color/briar_text_link</item>
<item name="android:windowBackground">@color/window_background</item>
<item name="android:windowAnimationStyle">@style/ActivityAnimation</item>

View File

@@ -61,7 +61,7 @@ public class PasswordFragmentTest {
String safePass = "really.safe.password";
passwordFragment.setupController = setupController;
when(setupController.needToShowDozeFragment()).thenReturn(false);
when(setupController.needsDozeWhitelisting()).thenReturn(false);
when(setupController.estimatePasswordStrength(safePass))
.thenReturn(STRONG);

View File

@@ -17,8 +17,8 @@ import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
@NotNullByDefault
public interface BlogPostFactory {
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
String SIGNING_LABEL_COMMENT = CLIENT_ID + "/COMMENT";
String SIGNING_LABEL_POST = CLIENT_ID.getString() + "/POST";
String SIGNING_LABEL_COMMENT = CLIENT_ID.getString() + "/COMMENT";
BlogPost createBlogPost(GroupId groupId, long timestamp,
@Nullable MessageId parent, LocalAuthor author, String body)

View File

@@ -16,7 +16,7 @@ import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
@NotNullByDefault
public interface ForumPostFactory {
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
String SIGNING_LABEL_POST = CLIENT_ID.getString() + "/POST";
@CryptoExecutor
ForumPost createPost(GroupId groupId, long timestamp,

View File

@@ -13,8 +13,8 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT
@NotNullByDefault
public interface GroupMessageFactory {
String SIGNING_LABEL_JOIN = CLIENT_ID + "/JOIN";
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
String SIGNING_LABEL_JOIN = CLIENT_ID.getString() + "/JOIN";
String SIGNING_LABEL_POST = CLIENT_ID.getString() + "/POST";
/**
* Creates a join announcement message for the creator of a group.

View File

@@ -12,7 +12,7 @@ import static org.briarproject.briar.api.privategroup.invitation.GroupInvitation
@NotNullByDefault
public interface GroupInvitationFactory {
String SIGNING_LABEL_INVITE = CLIENT_ID + "/INVITE";
String SIGNING_LABEL_INVITE = CLIENT_ID.getString() + "/INVITE";
/**
* Returns a signature to include when inviting a member to join a private

View File

@@ -13,20 +13,20 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
implementation 'org.jsoup:jsoup:1.10.3'
apt 'com.google.dagger:dagger-compiler:2.0.2'
apt "com.google.dagger:dagger-compiler:$daggerVersion"
testImplementation project(path: ':bramble-core', configuration: 'default')
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'net.jodah:concurrentunit:0.4.2'
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.jmock:jmock:$jmockVersion"
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
testApt 'com.google.dagger:dagger-compiler:2.0.2'
testApt "com.google.dagger:dagger-compiler:$daggerVersion"
}
dependencyVerification {
@@ -45,6 +45,7 @@ dependencyVerification {
'com.squareup.okio:okio:1.13.0:okio-1.13.0.jar:734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
'net.jodah:concurrentunit:0.4.2:concurrentunit-0.4.2.jar:5583078e1acf91734939e985bc9e7ee947b0e93a8eef679da6bb07bbeb47ced3',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',

View File

@@ -98,7 +98,8 @@ class IntroduceeManager {
private static final Logger LOG =
Logger.getLogger(IntroduceeManager.class.getName());
static final String SIGNING_LABEL_RESPONSE = CLIENT_ID + "/RESPONSE";
static final String SIGNING_LABEL_RESPONSE =
CLIENT_ID.getString() + "/RESPONSE";
private final MessageSender messageSender;
private final DatabaseComponent db;

View File

@@ -21,22 +21,34 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'net.ltgt.gradle:gradle-apt-plugin:0.9'
classpath 'de.undercouch:gradle-download-task:3.2.0'
classpath 'de.undercouch:gradle-download-task:3.3.0'
classpath files('libs/gradle-witness.jar')
}
}
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
ext.useJava6StandardLibrary = { task ->
def home = System.env.JAVA_6_HOME;
if (home != null && !home.isEmpty()) {
println "Setting Java 6 bootstrap classpath for ${task.name}"
task.dependsOn createJavaLangInvokeJar
task.options.bootstrapClasspath = files(
"${project.rootDir}/build/invoke.jar",
"${home}/jre/lib/rt.jar",
"${home}/jre/lib/jsse.jar"
)
ext {
// Define common library version centrally
daggerVersion = '2.0.2'
supportVersion = '27.0.1'
junitVersion = '4.12'
jmockVersion = '2.8.2'
hamcrestVersion = '1.3'
torVersion = '0.2.9.12'
geoipVersion = '2017-09-06'
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
useJava6StandardLibrary = { task ->
def home = System.env.JAVA_6_HOME;
if (home != null && !home.isEmpty()) {
println "Setting Java 6 bootstrap classpath for ${task.name}"
task.dependsOn createJavaLangInvokeJar
task.options.bootstrapClasspath = files(
"${project.rootDir}/build/invoke.jar",
"${home}/jre/lib/rt.jar",
"${home}/jre/lib/jsse.jar"
)
}
}
}