mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Compare commits
32 Commits
release-1.
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f31219d54b | ||
|
|
b0ea32c85f | ||
|
|
651e0b9859 | ||
|
|
f66244b578 | ||
|
|
3a35effae9 | ||
|
|
97f4cd039a | ||
|
|
20a1474457 | ||
|
|
f214208b0a | ||
|
|
d95a5fd58c | ||
|
|
7d4de21be0 | ||
|
|
a65bda04bf | ||
|
|
41ae7b0522 | ||
|
|
c2214f5e61 | ||
|
|
75bd7927ac | ||
|
|
ed2c0336ed | ||
|
|
b23baf70b4 | ||
|
|
17a7144194 | ||
|
|
0f7d27cd95 | ||
|
|
6735e5075b | ||
|
|
135cf086f6 | ||
|
|
72bac59989 | ||
|
|
2c99a75b4e | ||
|
|
5c068ed07b | ||
|
|
fec384c200 | ||
|
|
89a4d1922b | ||
|
|
6ed16802ce | ||
|
|
7f11d7280f | ||
|
|
597e2a233f | ||
|
|
dcbb3e76d4 | ||
|
|
286937e472 | ||
|
|
a3b5ff0bc0 | ||
|
|
1192f66487 |
@@ -8,20 +8,23 @@ cache:
|
|||||||
before_script:
|
before_script:
|
||||||
- set -e
|
- set -e
|
||||||
- export GRADLE_USER_HOME=$PWD/.gradle
|
- export GRADLE_USER_HOME=$PWD/.gradle
|
||||||
# Download OpenJDK 6 so we can compile against its standard library
|
|
||||||
- JDK_FILE=openjdk-6-jre-headless_6b38-1.13.10-1~deb7u1_amd64.deb
|
|
||||||
- if [ ! -d openjdk ]
|
|
||||||
- then
|
|
||||||
- wget -q http://ftp.uk.debian.org/debian/pool/main/o/openjdk-6/$JDK_FILE
|
|
||||||
- dpkg-deb -x $JDK_FILE openjdk
|
|
||||||
- fi
|
|
||||||
- export JAVA_6_HOME=$PWD/openjdk/usr/lib/jvm/java-6-openjdk-amd64
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
script:
|
script:
|
||||||
- ./gradlew test
|
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
|
||||||
|
- ./gradlew --no-daemon test
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
# this file changes every time but should not be cached
|
# these file change every time but should not be cached
|
||||||
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
||||||
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
||||||
|
|
||||||
|
test_reproducible:
|
||||||
|
image: briar/reproducer:latest
|
||||||
|
script:
|
||||||
|
- cd .. && mv briar /opt/briar-reproducer/
|
||||||
|
- cd /opt/briar-reproducer
|
||||||
|
- ./reproduce.py ${CI_COMMIT_REF_NAME}
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10003
|
versionCode 10004
|
||||||
versionName "1.0.3"
|
versionName "1.0.4"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.plugin.BackoffFactory;
|
|||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
@@ -38,15 +37,14 @@ public class AndroidPluginModule {
|
|||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
AndroidExecutor androidExecutor, SecureRandom random,
|
AndroidExecutor androidExecutor, SecureRandom random,
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
Application app, LocationUtils locationUtils, DevReporter reporter,
|
Application app, LocationUtils locationUtils, EventBus eventBus) {
|
||||||
EventBus eventBus) {
|
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth =
|
DuplexPluginFactory bluetooth =
|
||||||
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
||||||
appContext, random, eventBus, backoffFactory);
|
appContext, random, eventBus, backoffFactory);
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
|
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
|
||||||
appContext, locationUtils, reporter, eventBus,
|
appContext, locationUtils, eventBus, torSocketFactory,
|
||||||
torSocketFactory, backoffFactory);
|
backoffFactory);
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
scheduler, backoffFactory, appContext);
|
scheduler, backoffFactory, appContext);
|
||||||
Collection<DuplexPluginFactory> duplex =
|
Collection<DuplexPluginFactory> duplex =
|
||||||
|
|||||||
@@ -32,11 +32,9 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -114,7 +112,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final DevReporter reporter;
|
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
@@ -136,14 +133,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
||||||
Context appContext, LocationUtils locationUtils,
|
Context appContext, LocationUtils locationUtils,
|
||||||
DevReporter reporter, SocketFactory torSocketFactory,
|
SocketFactory torSocketFactory, Backoff backoff,
|
||||||
Backoff backoff, DuplexPluginCallback callback,
|
DuplexPluginCallback callback, String architecture,
|
||||||
String architecture, int maxLatency, int maxIdleTime) {
|
int maxLatency, int maxIdleTime) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.reporter = reporter;
|
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
@@ -389,14 +385,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendDevReports() {
|
|
||||||
ioExecutor.execute(() -> {
|
|
||||||
// TODO: Trigger this with a TransportEnabledEvent
|
|
||||||
File reportDir = AndroidUtils.getReportDir(appContext);
|
|
||||||
reporter.sendReports(reportDir);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
// If there's already a port number stored in config, reuse it
|
// If there's already a port number stored in config, reuse it
|
||||||
@@ -624,10 +612,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
connectionStatus.getAndSetCircuitBuilt()) {
|
connectionStatus.getAndSetCircuitBuilt()) {
|
||||||
LOG.info("First circuit built");
|
LOG.info("First circuit built");
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) {
|
if (isRunning()) callback.transportEnabled();
|
||||||
sendDevReports();
|
|
||||||
callback.transportEnabled();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,10 +641,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
||||||
connectionStatus.setBootstrapped();
|
connectionStatus.setBootstrapped();
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) {
|
if (isRunning()) callback.transportEnabled();
|
||||||
sendDevReports();
|
|
||||||
callback.transportEnabled();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
|
||||||
@@ -40,21 +39,18 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final DevReporter reporter;
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
|
||||||
public TorPluginFactory(Executor ioExecutor,
|
public TorPluginFactory(Executor ioExecutor,
|
||||||
ScheduledExecutorService scheduler, Context appContext,
|
ScheduledExecutorService scheduler, Context appContext,
|
||||||
LocationUtils locationUtils, DevReporter reporter,
|
LocationUtils locationUtils, EventBus eventBus,
|
||||||
EventBus eventBus, SocketFactory torSocketFactory,
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory) {
|
||||||
BackoffFactory backoffFactory) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.reporter = reporter;
|
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
@@ -94,7 +90,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
||||||
locationUtils, reporter, torSocketFactory, backoff, callback,
|
locationUtils, torSocketFactory, backoff, callback,
|
||||||
architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.net.wifi.WifiConfiguration;
|
|||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.StrictMode;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
@@ -66,9 +67,12 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void writeSeed() {
|
protected void writeSeed() {
|
||||||
|
// Silence strict mode
|
||||||
|
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
||||||
super.writeSeed();
|
super.writeSeed();
|
||||||
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
||||||
applyOpenSslFix();
|
applyOpenSslFix();
|
||||||
|
StrictMode.setThreadPolicy(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -14,6 +15,8 @@ dependencies {
|
|||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -26,6 +29,9 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
'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.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
@@ -33,6 +39,7 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -48,8 +55,3 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
useJava6StandardLibrary(it)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ public interface ContactManager {
|
|||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
*/
|
*/
|
||||||
ContactId addContact(Author remote, AuthorId local,
|
ContactId addContact(Author remote, AuthorId local, SecretKey master,
|
||||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
long timestamp, boolean alice, boolean verified, boolean active)
|
||||||
boolean active) throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given ID.
|
* Returns the contact with the given ID.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.io.IOException;
|
|||||||
public interface BdfReader {
|
public interface BdfReader {
|
||||||
|
|
||||||
int DEFAULT_NESTED_LIMIT = 5;
|
int DEFAULT_NESTED_LIMIT = 5;
|
||||||
|
int DEFAULT_MAX_BUFFER_SIZE = 64 * 1024;
|
||||||
|
|
||||||
boolean eof() throws IOException;
|
boolean eof() throws IOException;
|
||||||
|
|
||||||
@@ -39,13 +40,13 @@ public interface BdfReader {
|
|||||||
|
|
||||||
boolean hasString() throws IOException;
|
boolean hasString() throws IOException;
|
||||||
|
|
||||||
String readString(int maxLength) throws IOException;
|
String readString() throws IOException;
|
||||||
|
|
||||||
void skipString() throws IOException;
|
void skipString() throws IOException;
|
||||||
|
|
||||||
boolean hasRaw() throws IOException;
|
boolean hasRaw() throws IOException;
|
||||||
|
|
||||||
byte[] readRaw(int maxLength) throws IOException;
|
byte[] readRaw() throws IOException;
|
||||||
|
|
||||||
void skipRaw() throws IOException;
|
void skipRaw() throws IOException;
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ public interface BdfReaderFactory {
|
|||||||
|
|
||||||
BdfReader createReader(InputStream in);
|
BdfReader createReader(InputStream in);
|
||||||
|
|
||||||
BdfReader createReader(InputStream in, int nestedLimit);
|
BdfReader createReader(InputStream in, int nestedLimit,
|
||||||
|
int maxBufferSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,18 +104,12 @@ public interface DatabaseComponent {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, optionally binding them to the given
|
* Stores the given transport keys for the given contact and returns a
|
||||||
* contact, and returns a key set ID.
|
* key set ID.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(Transaction txn, @Nullable ContactId c,
|
KeySetId addTransportKeys(Transaction txn, ContactId c,
|
||||||
TransportKeys k) throws DbException;
|
TransportKeys k) throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given keys for the given transport to the given contact.
|
|
||||||
*/
|
|
||||||
void bindTransportKeys(Transaction txn, ContactId c, TransportId t,
|
|
||||||
KeySetId k) throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact for the given
|
* Returns true if the database contains the given contact for the given
|
||||||
* local pseudonym.
|
* local pseudonym.
|
||||||
|
|||||||
@@ -3,10 +3,14 @@ package org.briarproject.bramble.api.reporting;
|
|||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DevConfig {
|
public interface DevConfig {
|
||||||
|
|
||||||
PublicKey getDevPublicKey();
|
PublicKey getDevPublicKey();
|
||||||
|
|
||||||
String getDevOnionAddress();
|
String getDevOnionAddress();
|
||||||
|
|
||||||
|
File getReportDir();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ public interface DevReporter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends any reports previously stored on disk.
|
* Sends any reports previously stored on disk.
|
||||||
*
|
|
||||||
* @param reportDir the directory where reports are stored.
|
|
||||||
*/
|
*/
|
||||||
void sendReports(File reportDir);
|
void sendReports();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,48 +19,24 @@ public interface KeyManager {
|
|||||||
/**
|
/**
|
||||||
* Informs the key manager that a new contact has been added. Derives and
|
* Informs the key manager that a new contact has been added. Derives and
|
||||||
* stores a set of transport keys for communicating with the contact over
|
* stores a set of transport keys for communicating with the contact over
|
||||||
* each transport.
|
* each transport and returns the key set IDs.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@link StreamContext StreamContexts} for the contact can be created
|
* {@link StreamContext StreamContexts} for the contact can be created
|
||||||
* after this method has returned.
|
* after this method has returned.
|
||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
|
* @param active whether the derived keys can be used for outgoing streams
|
||||||
*/
|
*/
|
||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
long timestamp, boolean alice) throws DbException;
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
|
|
||||||
/**
|
|
||||||
* Derives and stores a set of unbound transport keys for each transport
|
|
||||||
* and returns the key set IDs.
|
|
||||||
* <p/>
|
|
||||||
* The keys must be bound before they can be used for incoming streams,
|
|
||||||
* and also activated before they can be used for outgoing streams.
|
|
||||||
*
|
|
||||||
* @param alice true if the local party is Alice
|
|
||||||
*/
|
|
||||||
Map<TransportId, KeySetId> addUnboundKeys(Transaction txn, SecretKey master,
|
|
||||||
long timestamp, boolean alice) throws DbException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given transport keys to the given contact.
|
|
||||||
*/
|
|
||||||
void bindKeys(Transaction txn, ContactId c, Map<TransportId, KeySetId> keys)
|
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams. Keys must
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
* be bound before they are activated.
|
|
||||||
*/
|
*/
|
||||||
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the given transport keys, which must not have been bound, from
|
|
||||||
* the manager and the database.
|
|
||||||
*/
|
|
||||||
void removeKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we have keys that can be used for outgoing streams to
|
* Returns true if we have keys that can be used for outgoing streams to
|
||||||
* the given contact over the given transport.
|
* the given contact over the given transport.
|
||||||
|
|||||||
@@ -3,23 +3,20 @@ package org.briarproject.bramble.api.transport;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of transport keys for communicating with a contact. If the keys have
|
* A set of transport keys for communicating with a contact.
|
||||||
* not yet been bound to a contact, {@link #getContactId()}} returns null.
|
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class KeySet {
|
public class KeySet {
|
||||||
|
|
||||||
private final KeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
@Nullable
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final TransportKeys transportKeys;
|
private final TransportKeys transportKeys;
|
||||||
|
|
||||||
public KeySet(KeySetId keySetId, @Nullable ContactId contactId,
|
public KeySet(KeySetId keySetId, ContactId contactId,
|
||||||
TransportKeys transportKeys) {
|
TransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
@@ -30,7 +27,6 @@ public class KeySet {
|
|||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'net.ltgt.apt'
|
apply plugin: 'net.ltgt.apt'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
@@ -26,6 +27,8 @@ dependencies {
|
|||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -44,6 +47,9 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
||||||
@@ -52,6 +58,7 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
||||||
]
|
]
|
||||||
@@ -68,8 +75,3 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
useJava6StandardLibrary(it)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.briarproject.bramble.identity.IdentityModule;
|
|||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
|
import org.briarproject.bramble.reporting.ReportingModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.transport.TransportModule;
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
@@ -28,6 +29,8 @@ public interface BrambleCoreEagerSingletons {
|
|||||||
|
|
||||||
void inject(PropertiesModule.EagerSingletons init);
|
void inject(PropertiesModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(ReportingModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(SyncModule.EagerSingletons init);
|
void inject(SyncModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(SystemModule.EagerSingletons init);
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public class BrambleCoreModule {
|
|||||||
c.inject(new LifecycleModule.EagerSingletons());
|
c.inject(new LifecycleModule.EagerSingletons());
|
||||||
c.inject(new PluginModule.EagerSingletons());
|
c.inject(new PluginModule.EagerSingletons());
|
||||||
c.inject(new PropertiesModule.EagerSingletons());
|
c.inject(new PropertiesModule.EagerSingletons());
|
||||||
|
c.inject(new ReportingModule.EagerSingletons());
|
||||||
c.inject(new SyncModule.EagerSingletons());
|
c.inject(new SyncModule.EagerSingletons());
|
||||||
c.inject(new SystemModule.EagerSingletons());
|
c.inject(new SystemModule.EagerSingletons());
|
||||||
c.inject(new TransportModule.EagerSingletons());
|
c.inject(new TransportModule.EagerSingletons());
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||||
boolean active) throws DbException {
|
boolean active) throws DbException {
|
||||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||||
keyManager.addContact(txn, c, master, timestamp, alice);
|
keyManager.addContact(txn, c, master, timestamp, alice, active);
|
||||||
Contact contact = db.getContact(txn, c);
|
Contact contact = db.getContact(txn, c);
|
||||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||||
return c;
|
return c;
|
||||||
|
|||||||
@@ -152,59 +152,47 @@ public class MessageEncrypter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) {
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
}
|
}
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
|
||||||
if (args[0].equals("generate")) {
|
if (args[0].equals("generate")) {
|
||||||
if (args.length != 3) {
|
if (args.length != 3) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
generateKeyPair(args[1], args[2]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(2);
|
||||||
}
|
}
|
||||||
// Generate a key pair
|
|
||||||
KeyPair keyPair = encrypter.generateKeyPair();
|
|
||||||
PrintStream out = new PrintStream(new FileOutputStream(args[1]));
|
|
||||||
out.print(
|
|
||||||
StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
out = new PrintStream(new FileOutputStream(args[2]));
|
|
||||||
out.print(
|
|
||||||
StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
} else if (args[0].equals("encrypt")) {
|
} else if (args[0].equals("encrypt")) {
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
encryptMessage(args[1]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(2);
|
||||||
}
|
}
|
||||||
// Encrypt a decrypted message
|
|
||||||
InputStream in = new FileInputStream(args[1]);
|
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
|
||||||
PublicKey publicKey =
|
|
||||||
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
|
||||||
String message = readFully(System.in);
|
|
||||||
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
|
||||||
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
|
||||||
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
|
||||||
} else if (args[0].equals("decrypt")) {
|
} else if (args[0].equals("decrypt")) {
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
decryptMessage(args[1]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(2);
|
||||||
}
|
}
|
||||||
// Decrypt an encrypted message
|
|
||||||
InputStream in = new FileInputStream(args[1]);
|
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
|
||||||
PrivateKey privateKey =
|
|
||||||
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
|
||||||
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
|
||||||
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
|
||||||
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
|
||||||
} else {
|
} else {
|
||||||
printUsage();
|
printUsage();
|
||||||
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +204,46 @@ public class MessageEncrypter {
|
|||||||
System.err.println("MessageEncrypter decrypt <private_key_file>");
|
System.err.println("MessageEncrypter decrypt <private_key_file>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void generateKeyPair(String publicKeyFile,
|
||||||
|
String privateKeyFile) throws Exception {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
|
KeyPair keyPair = encrypter.generateKeyPair();
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile));
|
||||||
|
out.print(StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
out = new PrintStream(new FileOutputStream(privateKeyFile));
|
||||||
|
out.print(StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void encryptMessage(String publicKeyFile) throws Exception {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
|
InputStream in = new FileInputStream(publicKeyFile);
|
||||||
|
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
||||||
|
PublicKey publicKey =
|
||||||
|
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
||||||
|
String message = readFully(System.in);
|
||||||
|
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
||||||
|
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
||||||
|
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void decryptMessage(String privateKeyFile) throws Exception {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
|
InputStream in = new FileInputStream(privateKeyFile);
|
||||||
|
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
||||||
|
PrivateKey privateKey =
|
||||||
|
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
||||||
|
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
||||||
|
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
||||||
|
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
|
||||||
private static String readFully(InputStream in) throws IOException {
|
private static String readFully(InputStream in) throws IOException {
|
||||||
String newline = System.getProperty("line.separator");
|
String newline = System.getProperty("line.separator");
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -16,11 +17,13 @@ class BdfReaderFactoryImpl implements BdfReaderFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in) {
|
public BdfReader createReader(InputStream in) {
|
||||||
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
|
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
|
DEFAULT_MAX_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in, int nestedLimit) {
|
public BdfReader createReader(InputStream in, int nestedLimit,
|
||||||
return new BdfReaderImpl(in, nestedLimit);
|
int maxBufferSize) {
|
||||||
|
return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,15 +37,16 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
private static final byte[] EMPTY_BUFFER = new byte[0];
|
private static final byte[] EMPTY_BUFFER = new byte[0];
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final int nestedLimit;
|
private final int nestedLimit, maxBufferSize;
|
||||||
|
|
||||||
private boolean hasLookahead = false, eof = false;
|
private boolean hasLookahead = false, eof = false;
|
||||||
private byte next;
|
private byte next;
|
||||||
private byte[] buf = new byte[8];
|
private byte[] buf = new byte[8];
|
||||||
|
|
||||||
BdfReaderImpl(InputStream in, int nestedLimit) {
|
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.nestedLimit = nestedLimit;
|
this.nestedLimit = nestedLimit;
|
||||||
|
this.maxBufferSize = maxBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readLookahead() throws IOException {
|
private void readLookahead() throws IOException {
|
||||||
@@ -91,8 +92,8 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
if (hasBoolean()) return readBoolean();
|
if (hasBoolean()) return readBoolean();
|
||||||
if (hasLong()) return readLong();
|
if (hasLong()) return readLong();
|
||||||
if (hasDouble()) return readDouble();
|
if (hasDouble()) return readDouble();
|
||||||
if (hasString()) return readString(Integer.MAX_VALUE);
|
if (hasString()) return readString();
|
||||||
if (hasRaw()) return readRaw(Integer.MAX_VALUE);
|
if (hasRaw()) return readRaw();
|
||||||
if (hasList()) return readList(level);
|
if (hasList()) return readList(level);
|
||||||
if (hasDictionary()) return readDictionary(level);
|
if (hasDictionary()) return readDictionary(level);
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
@@ -245,11 +246,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readString(int maxLength) throws IOException {
|
public String readString() throws IOException {
|
||||||
if (!hasString()) throw new FormatException();
|
if (!hasString()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
int length = readStringLength();
|
int length = readStringLength();
|
||||||
if (length < 0 || length > maxLength) throw new FormatException();
|
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||||
if (length == 0) return "";
|
if (length == 0) return "";
|
||||||
readIntoBuffer(length);
|
readIntoBuffer(length);
|
||||||
return new String(buf, 0, length, "UTF-8");
|
return new String(buf, 0, length, "UTF-8");
|
||||||
@@ -279,11 +280,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] readRaw(int maxLength) throws IOException {
|
public byte[] readRaw() throws IOException {
|
||||||
if (!hasRaw()) throw new FormatException();
|
if (!hasRaw()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
int length = readRawLength();
|
int length = readRawLength();
|
||||||
if (length < 0 || length > maxLength) throw new FormatException();
|
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||||
if (length == 0) return EMPTY_BUFFER;
|
if (length == 0) return EMPTY_BUFFER;
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
readIntoBuffer(b, length);
|
readIntoBuffer(b, length);
|
||||||
@@ -381,7 +382,7 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
BdfDictionary dictionary = new BdfDictionary();
|
BdfDictionary dictionary = new BdfDictionary();
|
||||||
readDictionaryStart();
|
readDictionaryStart();
|
||||||
while (!hasDictionaryEnd())
|
while (!hasDictionaryEnd())
|
||||||
dictionary.put(readString(Integer.MAX_VALUE), readObject(level + 1));
|
dictionary.put(readString(), readObject(level + 1));
|
||||||
readDictionaryEnd();
|
readDictionaryEnd();
|
||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ class MetadataParserImpl implements MetadataParser {
|
|||||||
if (reader.hasBoolean()) return reader.readBoolean();
|
if (reader.hasBoolean()) return reader.readBoolean();
|
||||||
if (reader.hasLong()) return reader.readLong();
|
if (reader.hasLong()) return reader.readLong();
|
||||||
if (reader.hasDouble()) return reader.readDouble();
|
if (reader.hasDouble()) return reader.readDouble();
|
||||||
if (reader.hasString()) return reader.readString(Integer.MAX_VALUE);
|
if (reader.hasString()) return reader.readString();
|
||||||
if (reader.hasRaw()) return reader.readRaw(Integer.MAX_VALUE);
|
if (reader.hasRaw()) return reader.readRaw();
|
||||||
if (reader.hasList()) return reader.readList();
|
if (reader.hasList()) return reader.readList();
|
||||||
if (reader.hasDictionary()) return reader.readDictionary();
|
if (reader.hasDictionary()) return reader.readDictionary();
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|||||||
@@ -125,16 +125,10 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, optionally binding them to the given
|
* Stores the given transport keys for the given contact and returns a
|
||||||
* contact, and returns a key set ID.
|
* key set ID.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(T txn, @Nullable ContactId c, TransportKeys k)
|
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given keys for the given transport to the given contact.
|
|
||||||
*/
|
|
||||||
void bindTransportKeys(T txn, ContactId c, TransportId t, KeySetId k)
|
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -234,27 +234,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Transaction transaction,
|
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
|
||||||
@Nullable ContactId c, TransportKeys k) throws DbException {
|
TransportKeys k) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
|
||||||
T txn = unbox(transaction);
|
|
||||||
if (c != null && !db.containsContact(txn, c))
|
|
||||||
throw new NoSuchContactException();
|
|
||||||
if (!db.containsTransport(txn, k.getTransportId()))
|
|
||||||
throw new NoSuchTransportException();
|
|
||||||
return db.addTransportKeys(txn, c, k);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindTransportKeys(Transaction transaction, ContactId c,
|
|
||||||
TransportId t, KeySetId k) throws DbException {
|
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, k.getTransportId()))
|
||||||
throw new NoSuchTransportException();
|
throw new NoSuchTransportException();
|
||||||
db.bindTransportKeys(txn, c, t, k);
|
return db.addTransportKeys(txn, c, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
@@ -74,7 +75,7 @@ import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
|
|||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
static final int CODE_SCHEMA_VERSION = 38;
|
static final int CODE_SCHEMA_VERSION = 39;
|
||||||
|
|
||||||
// Rotation period offsets for incoming transport keys
|
// Rotation period offsets for incoming transport keys
|
||||||
private static final int OFFSET_PREV = -1;
|
private static final int OFFSET_PREV = -1;
|
||||||
@@ -236,7 +237,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (transportId _STRING NOT NULL,"
|
+ " (transportId _STRING NOT NULL,"
|
||||||
+ " keySetId _COUNTER,"
|
+ " keySetId _COUNTER,"
|
||||||
+ " rotationPeriod BIGINT NOT NULL,"
|
+ " rotationPeriod BIGINT NOT NULL,"
|
||||||
+ " contactId INT," // Null if keys are not bound
|
+ " contactId INT NOT NULL,"
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
+ " tagKey _SECRET NOT NULL,"
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
+ " headerKey _SECRET NOT NULL,"
|
||||||
+ " stream BIGINT NOT NULL,"
|
+ " stream BIGINT NOT NULL,"
|
||||||
@@ -255,7 +256,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (transportId _STRING NOT NULL,"
|
+ " (transportId _STRING NOT NULL,"
|
||||||
+ " keySetId INT NOT NULL,"
|
+ " keySetId INT NOT NULL,"
|
||||||
+ " rotationPeriod BIGINT NOT NULL,"
|
+ " rotationPeriod BIGINT NOT NULL,"
|
||||||
+ " contactId INT," // Null if keys are not bound
|
+ " contactId INT NOT NULL,"
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
+ " tagKey _SECRET NOT NULL,"
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
+ " headerKey _SECRET NOT NULL,"
|
||||||
+ " base BIGINT NOT NULL,"
|
+ " base BIGINT NOT NULL,"
|
||||||
@@ -389,7 +390,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return Collections.emptyList();
|
return singletonList(new Migration38_39());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeSchemaVersion(Connection txn, int version)
|
private void storeSchemaVersion(Connection txn, int version)
|
||||||
@@ -883,7 +884,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Connection txn, @Nullable ContactId c,
|
public KeySetId addTransportKeys(Connection txn, ContactId c,
|
||||||
TransportKeys k) throws DbException {
|
TransportKeys k) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -893,8 +894,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " rotationPeriod, tagKey, headerKey, stream, active)"
|
+ " rotationPeriod, tagKey, headerKey, stream, active)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
if (c == null) ps.setNull(1, INTEGER);
|
ps.setInt(1, c.getInt());
|
||||||
else ps.setInt(1, c.getInt());
|
|
||||||
ps.setString(2, k.getTransportId().getString());
|
ps.setString(2, k.getTransportId().getString());
|
||||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
||||||
ps.setLong(3, outCurr.getRotationPeriod());
|
ps.setLong(3, outCurr.getRotationPeriod());
|
||||||
@@ -922,8 +922,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, keySetId.getInt());
|
ps.setInt(1, keySetId.getInt());
|
||||||
if (c == null) ps.setNull(2, INTEGER);
|
ps.setInt(2, c.getInt());
|
||||||
else ps.setInt(2, c.getInt());
|
|
||||||
ps.setString(3, k.getTransportId().getString());
|
ps.setString(3, k.getTransportId().getString());
|
||||||
// Previous rotation period
|
// Previous rotation period
|
||||||
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
||||||
@@ -965,33 +964,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindTransportKeys(Connection txn, ContactId c, TransportId t,
|
|
||||||
KeySetId k) throws DbException {
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
try {
|
|
||||||
String sql = "UPDATE outgoingKeys SET contactId = ?"
|
|
||||||
+ " WHERE keySetId = ?";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setInt(1, c.getInt());
|
|
||||||
ps.setInt(2, k.getInt());
|
|
||||||
int affected = ps.executeUpdate();
|
|
||||||
if (affected < 0) throw new DbStateException();
|
|
||||||
ps.close();
|
|
||||||
sql = "UPDATE incomingKeys SET contactId = ?"
|
|
||||||
+ " WHERE keySetId = ?";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setInt(1, c.getInt());
|
|
||||||
ps.setInt(2, k.getInt());
|
|
||||||
affected = ps.executeUpdate();
|
|
||||||
if (affected < 0) throw new DbStateException();
|
|
||||||
ps.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
tryToClose(ps);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsContact(Connection txn, AuthorId remote,
|
public boolean containsContact(Connection txn, AuthorId remote,
|
||||||
AuthorId local) throws DbException {
|
AuthorId local) throws DbException {
|
||||||
@@ -2172,7 +2144,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
|
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
|
||||||
KeySetId keySetId = new KeySetId(rs.getInt(1));
|
KeySetId keySetId = new KeySetId(rs.getInt(1));
|
||||||
ContactId contactId = new ContactId(rs.getInt(2));
|
ContactId contactId = new ContactId(rs.getInt(2));
|
||||||
if (rs.wasNull()) contactId = null;
|
|
||||||
long rotationPeriod = rs.getLong(3);
|
long rotationPeriod = rs.getLong(3);
|
||||||
SecretKey tagKey = new SecretKey(rs.getBytes(4));
|
SecretKey tagKey = new SecretKey(rs.getBytes(4));
|
||||||
SecretKey headerKey = new SecretKey(rs.getBytes(5));
|
SecretKey headerKey = new SecretKey(rs.getBytes(5));
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
class Migration38_39 implements Migration<Connection> {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(Migration38_39.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStartVersion() {
|
||||||
|
return 38;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEndVersion() {
|
||||||
|
return 39;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(Connection txn) throws DbException {
|
||||||
|
Statement s = null;
|
||||||
|
try {
|
||||||
|
s = txn.createStatement();
|
||||||
|
// Add not null constraints
|
||||||
|
s.execute("ALTER TABLE outgoingKeys"
|
||||||
|
+ " ALTER COLUMN contactId"
|
||||||
|
+ " SET NOT NULL");
|
||||||
|
s.execute("ALTER TABLE incomingKeys"
|
||||||
|
+ " ALTER COLUMN contactId"
|
||||||
|
+ " SET NOT NULL");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(s);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryToClose(@Nullable Statement s) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorConstants;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
@@ -18,17 +23,19 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class DevReporterImpl implements DevReporter {
|
class DevReporterImpl implements DevReporter, EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DevReporterImpl.class.getName());
|
Logger.getLogger(DevReporterImpl.class.getName());
|
||||||
@@ -36,12 +43,15 @@ class DevReporterImpl implements DevReporter {
|
|||||||
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
||||||
private static final int LINE_LENGTH = 70;
|
private static final int LINE_LENGTH = 70;
|
||||||
|
|
||||||
|
private final Executor ioExecutor;
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final DevConfig devConfig;
|
private final DevConfig devConfig;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
|
|
||||||
DevReporterImpl(CryptoComponent crypto, DevConfig devConfig,
|
@Inject
|
||||||
SocketFactory torSocketFactory) {
|
DevReporterImpl(@IoExecutor Executor ioExecutor, CryptoComponent crypto,
|
||||||
|
DevConfig devConfig, SocketFactory torSocketFactory) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.devConfig = devConfig;
|
this.devConfig = devConfig;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
@@ -63,6 +73,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
@Override
|
@Override
|
||||||
public void encryptReportToFile(File reportDir, String filename,
|
public void encryptReportToFile(File reportDir, String filename,
|
||||||
String report) throws FileNotFoundException {
|
String report) throws FileNotFoundException {
|
||||||
|
LOG.info("Encrypting report to file");
|
||||||
byte[] plaintext = StringUtils.toUtf8(report);
|
byte[] plaintext = StringUtils.toUtf8(report);
|
||||||
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
|
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
|
||||||
plaintext);
|
plaintext);
|
||||||
@@ -82,7 +93,17 @@ class DevReporterImpl implements DevReporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendReports(File reportDir) {
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof TransportEnabledEvent) {
|
||||||
|
TransportEnabledEvent t = (TransportEnabledEvent) e;
|
||||||
|
if (t.getTransportId().equals(TorConstants.ID))
|
||||||
|
ioExecutor.execute(this::sendReports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendReports() {
|
||||||
|
File reportDir = devConfig.getReportDir();
|
||||||
File[] reports = reportDir.listFiles();
|
File[] reports = reportDir.listFiles();
|
||||||
if (reports == null || reports.length == 0)
|
if (reports == null || reports.length == 0)
|
||||||
return; // No reports to send
|
return; // No reports to send
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -12,9 +12,16 @@ import dagger.Provides;
|
|||||||
@Module
|
@Module
|
||||||
public class ReportingModule {
|
public class ReportingModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
DevReporter devReporter;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
DevReporter provideDevReporter(CryptoComponent crypto,
|
@Singleton
|
||||||
DevConfig devConfig, SocketFactory torSocketFactory) {
|
DevReporter provideDevReporter(DevReporterImpl devReporter,
|
||||||
return new DevReporterImpl(crypto, devConfig, torSocketFactory);
|
EventBus eventBus) {
|
||||||
|
eventBus.addListener(devReporter);
|
||||||
|
return devReporter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,39 +99,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
public Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
long timestamp, boolean alice) throws DbException {
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
for (TransportKeyManager m : managers.values())
|
|
||||||
m.addContact(txn, c, master, timestamp, alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<TransportId, KeySetId> addUnboundKeys(Transaction txn,
|
|
||||||
SecretKey master, long timestamp, boolean alice)
|
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Map<TransportId, KeySetId> ids = new HashMap<>();
|
Map<TransportId, KeySetId> ids = new HashMap<>();
|
||||||
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
||||||
TransportId t = e.getKey();
|
TransportId t = e.getKey();
|
||||||
TransportKeyManager m = e.getValue();
|
TransportKeyManager m = e.getValue();
|
||||||
ids.put(t, m.addUnboundKeys(txn, master, timestamp, alice));
|
ids.put(t, m.addContact(txn, c, master, timestamp, alice, active));
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindKeys(Transaction txn, ContactId c,
|
|
||||||
Map<TransportId, KeySetId> keys) throws DbException {
|
|
||||||
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
|
||||||
TransportId t = e.getKey();
|
|
||||||
TransportKeyManager m = managers.get(t);
|
|
||||||
if (m == null) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
|
||||||
} else {
|
|
||||||
m.bindKeys(txn, c, e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -146,24 +125,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
|
||||||
throws DbException {
|
|
||||||
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
|
||||||
TransportId t = e.getKey();
|
|
||||||
TransportKeyManager m = managers.get(t);
|
|
||||||
if (m == null) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
|
||||||
} else {
|
|
||||||
m.removeKeys(txn, e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
|
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
|
||||||
TransportKeyManager m = managers.get(t);
|
TransportKeyManager m = managers.get(t);
|
||||||
return m == null ? false : m.canSendOutgoingStreams(c);
|
return m != null && m.canSendOutgoingStreams(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,32 +3,28 @@ package org.briarproject.bramble.transport;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
class MutableKeySet {
|
||||||
|
|
||||||
public class MutableKeySet {
|
|
||||||
|
|
||||||
private final KeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
@Nullable
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final MutableTransportKeys transportKeys;
|
private final MutableTransportKeys transportKeys;
|
||||||
|
|
||||||
public MutableKeySet(KeySetId keySetId, @Nullable ContactId contactId,
|
MutableKeySet(KeySetId keySetId, ContactId contactId,
|
||||||
MutableTransportKeys transportKeys) {
|
MutableTransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.transportKeys = transportKeys;
|
this.transportKeys = transportKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeySetId getKeySetId() {
|
KeySetId getKeySetId() {
|
||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
ContactId getContactId() {
|
||||||
public ContactId getContactId() {
|
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableTransportKeys getTransportKeys() {
|
MutableTransportKeys getTransportKeys() {
|
||||||
return transportKeys;
|
return transportKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,18 +15,11 @@ interface TransportKeyManager {
|
|||||||
|
|
||||||
void start(Transaction txn) throws DbException;
|
void start(Transaction txn) throws DbException;
|
||||||
|
|
||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException;
|
long timestamp, boolean alice, boolean active) throws DbException;
|
||||||
|
|
||||||
KeySetId addUnboundKeys(Transaction txn, SecretKey master, long timestamp,
|
|
||||||
boolean alice) throws DbException;
|
|
||||||
|
|
||||||
void bindKeys(Transaction txn, ContactId c, KeySetId k) throws DbException;
|
|
||||||
|
|
||||||
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
||||||
|
|
||||||
void removeKeys(Transaction txn, KeySetId k) throws DbException;
|
|
||||||
|
|
||||||
void removeContact(ContactId c);
|
void removeContact(ContactId c);
|
||||||
|
|
||||||
boolean canSendOutgoingStreams(ContactId c);
|
boolean canSendOutgoingStreams(ContactId c);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
@@ -119,16 +118,14 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
private void addKeys(KeySetId keySetId, @Nullable ContactId contactId,
|
private void addKeys(KeySetId keySetId, ContactId contactId,
|
||||||
MutableTransportKeys m) {
|
MutableTransportKeys m) {
|
||||||
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
||||||
keys.put(keySetId, ks);
|
keys.put(keySetId, ks);
|
||||||
if (contactId != null) {
|
encodeTags(keySetId, contactId, m.getPreviousIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getPreviousIncomingKeys());
|
encodeTags(keySetId, contactId, m.getCurrentIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getCurrentIncomingKeys());
|
encodeTags(keySetId, contactId, m.getNextIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getNextIncomingKeys());
|
considerReplacingOutgoingKeys(ks);
|
||||||
considerReplacingOutgoingKeys(ks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
@@ -150,8 +147,9 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
if (ks.getTransportKeys().getCurrentOutgoingKeys().isActive()) {
|
if (ks.getTransportKeys().getCurrentOutgoingKeys().isActive()) {
|
||||||
MutableKeySet old = outContexts.get(ks.getContactId());
|
MutableKeySet old = outContexts.get(ks.getContactId());
|
||||||
if (old == null ||
|
if (old == null ||
|
||||||
old.getKeySetId().getInt() < ks.getKeySetId().getInt())
|
old.getKeySetId().getInt() < ks.getKeySetId().getInt()) {
|
||||||
outContexts.put(ks.getContactId(), ks);
|
outContexts.put(ks.getContactId(), ks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,20 +175,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
public KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException {
|
long timestamp, boolean alice, boolean active) throws DbException {
|
||||||
deriveAndAddKeys(txn, c, master, timestamp, alice, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeySetId addUnboundKeys(Transaction txn, SecretKey master,
|
|
||||||
long timestamp, boolean alice) throws DbException {
|
|
||||||
return deriveAndAddKeys(txn, null, master, timestamp, alice, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private KeySetId deriveAndAddKeys(Transaction txn, @Nullable ContactId c,
|
|
||||||
SecretKey master, long timestamp, boolean alice, boolean active)
|
|
||||||
throws DbException {
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Work out what rotation period the timestamp belongs to
|
// Work out what rotation period the timestamp belongs to
|
||||||
@@ -211,31 +197,12 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindKeys(Transaction txn, ContactId c, KeySetId k)
|
|
||||||
throws DbException {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
MutableKeySet ks = keys.get(k);
|
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
|
||||||
// Check that the keys haven't already been bound
|
|
||||||
if (ks.getContactId() != null) throw new IllegalArgumentException();
|
|
||||||
MutableTransportKeys m = ks.getTransportKeys();
|
|
||||||
addKeys(k, c, m);
|
|
||||||
db.bindTransportKeys(txn, c, m.getTransportId(), k);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
MutableKeySet ks = keys.get(k);
|
MutableKeySet ks = keys.get(k);
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
if (ks == null) throw new IllegalArgumentException();
|
||||||
// Check that the keys have been bound
|
|
||||||
if (ks.getContactId() == null) throw new IllegalArgumentException();
|
|
||||||
MutableTransportKeys m = ks.getTransportKeys();
|
MutableTransportKeys m = ks.getTransportKeys();
|
||||||
m.getCurrentOutgoingKeys().activate();
|
m.getCurrentOutgoingKeys().activate();
|
||||||
considerReplacingOutgoingKeys(ks);
|
considerReplacingOutgoingKeys(ks);
|
||||||
@@ -245,21 +212,6 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeKeys(Transaction txn, KeySetId k) throws DbException {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
MutableKeySet ks = keys.remove(k);
|
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
|
||||||
// Check that the keys haven't been bound
|
|
||||||
if (ks.getContactId() != null) throw new IllegalArgumentException();
|
|
||||||
TransportId t = ks.getTransportKeys().getTransportId();
|
|
||||||
db.removeTransportKeys(txn, t, k);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeContact(ContactId c) {
|
public void removeContact(ContactId c) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).addContact(txn, remote, local, verified, active);
|
oneOf(db).addContact(txn, remote, local, verified, active);
|
||||||
will(returnValue(contactId));
|
will(returnValue(contactId));
|
||||||
oneOf(keyManager)
|
oneOf(keyManager).addContact(txn, contactId, master, timestamp,
|
||||||
.addContact(txn, contactId, master, timestamp, alice);
|
alice, active);
|
||||||
oneOf(db).getContact(txn, contactId);
|
oneOf(db).getContact(txn, contactId);
|
||||||
will(returnValue(contact));
|
will(returnValue(contact));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||||
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -158,30 +161,32 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString8() throws Exception {
|
public void testReadString8() throws Exception {
|
||||||
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
assertEquals("foo", r.readString());
|
||||||
assertEquals("", r.readString(Integer.MAX_VALUE));
|
assertEquals("", r.readString());
|
||||||
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString8ChecksMaxLength() throws Exception {
|
public void testReadString8ChecksMaxLength() throws Exception {
|
||||||
// "foo" twice
|
int maxBufferSize = 3;
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "03" + "666F6F");
|
// "foo", "fooo"
|
||||||
assertEquals("foo", r.readString(3));
|
setContents("41" + "03" + "666F6F"
|
||||||
|
+ "41" + "04" + "666F6F6F", maxBufferSize);
|
||||||
|
assertEquals("foo", r.readString());
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString(2);
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString8() throws Exception {
|
public void testSkipString8() throws Exception {
|
||||||
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
@@ -193,34 +198,37 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString16() throws Exception {
|
public void testReadString16() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 -1 random letters
|
// 128 random letters and 2^15 -1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
assertEquals(shortest, r.readString());
|
||||||
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString16ChecksMaxLength() throws Exception {
|
public void testReadString16ChecksMaxLength() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
int maxBufferSize = Byte.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String valid = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
// 128 random letters, twice
|
String validHex = toHexString(valid.getBytes("UTF-8"));
|
||||||
setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex);
|
String invalidhex = validHex + "20";
|
||||||
assertEquals(shortest, r.readString(Byte.MAX_VALUE + 1));
|
// 128 random letters, the same plus a space
|
||||||
|
setContents("42" + "0080" + validHex
|
||||||
|
+ "42" + "0081" + invalidhex, maxBufferSize);
|
||||||
|
assertEquals(valid, r.readString());
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString(Byte.MAX_VALUE);
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString16() throws Exception {
|
public void testSkipString16() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 - 1 random letters
|
// 128 random letters and 2^15 - 1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
r.skipString();
|
r.skipString();
|
||||||
@@ -230,30 +238,32 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString32() throws Exception {
|
public void testReadString32() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters
|
// 2^15 random letters
|
||||||
setContents("44" + "00008000" + shortHex);
|
setContents("44" + "00008000" + shortHex);
|
||||||
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
assertEquals(shortest, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString32ChecksMaxLength() throws Exception {
|
public void testReadString32ChecksMaxLength() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
int maxBufferSize = Short.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String valid = getRandomString(maxBufferSize);
|
||||||
// 2^15 random letters, twice
|
String validHex = toHexString(valid.getBytes("UTF-8"));
|
||||||
setContents("44" + "00008000" + shortHex +
|
String invalidHex = validHex + "20";
|
||||||
"44" + "00008000" + shortHex);
|
// 2^15 random letters, the same plus a space
|
||||||
assertEquals(shortest, r.readString(Short.MAX_VALUE + 1));
|
setContents("44" + "00008000" + validHex +
|
||||||
|
"44" + "00008001" + invalidHex, maxBufferSize);
|
||||||
|
assertEquals(valid, r.readString());
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString(Short.MAX_VALUE);
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString32() throws Exception {
|
public void testSkipString32() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters, twice
|
// 2^15 random letters, twice
|
||||||
setContents("44" + "00008000" + shortHex +
|
setContents("44" + "00008000" + shortHex +
|
||||||
"44" + "00008000" + shortHex);
|
"44" + "00008000" + shortHex);
|
||||||
@@ -265,41 +275,43 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadUtf8String() throws Exception {
|
public void testReadUtf8String() throws Exception {
|
||||||
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
||||||
String hex = StringUtils.toHexString(unicode.getBytes("UTF-8"));
|
String hex = toHexString(unicode.getBytes("UTF-8"));
|
||||||
// STRING_8 tag, "foo", the empty string, and the test string
|
// STRING_8 tag, "foo", the empty string, and the test string
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
||||||
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
assertEquals("foo", r.readString());
|
||||||
assertEquals("", r.readString(Integer.MAX_VALUE));
|
assertEquals("", r.readString());
|
||||||
assertEquals(unicode, r.readString(Integer.MAX_VALUE));
|
assertEquals(unicode, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadRaw8() throws Exception {
|
public void testReadRaw8() throws Exception {
|
||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("51" + "03" + "010203" + "51" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"51" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw());
|
||||||
assertArrayEquals(new byte[0], r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(new byte[0], r.readRaw());
|
||||||
assertArrayEquals(longest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(longest, r.readRaw());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw8ChecksMaxLength() throws Exception {
|
public void testReadRaw8ChecksMaxLength() throws Exception {
|
||||||
// {1, 2, 3} twice
|
int maxBufferSize = 3;
|
||||||
setContents("51" + "03" + "010203" + "51" + "03" + "010203");
|
// {1, 2, 3}, {1, 2, 3, 4}
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw(3));
|
setContents("51" + "03" + "010203" + "51" + "04" + "01020304",
|
||||||
|
maxBufferSize);
|
||||||
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw());
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw(2);
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw8() throws Exception {
|
public void testSkipRaw8() throws Exception {
|
||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("51" + "03" + "010203" + "51" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"51" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
@@ -312,33 +324,36 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadRaw16() throws Exception {
|
public void testReadRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
assertArrayEquals(shortest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(shortest, r.readRaw());
|
||||||
assertArrayEquals(longest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(longest, r.readRaw());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw16ChecksMaxLength() throws Exception {
|
public void testReadRaw16ChecksMaxLength() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
int maxBufferSize = Byte.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
byte[] valid = new byte[maxBufferSize];
|
||||||
// 128 zero bytes, twice
|
String validHex = toHexString(valid);
|
||||||
setContents("52" + "0080" + shortHex + "52" + "0080" + shortHex);
|
String invalidHex = validHex + "00";
|
||||||
assertArrayEquals(shortest, r.readRaw(Byte.MAX_VALUE + 1));
|
// 128 zero bytes, 129 zero bytes
|
||||||
|
setContents("52" + "0080" + validHex
|
||||||
|
+ "52" + "0081" + invalidHex, maxBufferSize);
|
||||||
|
assertArrayEquals(valid, r.readRaw());
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw(Byte.MAX_VALUE);
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw16() throws Exception {
|
public void testSkipRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
r.skipRaw();
|
r.skipRaw();
|
||||||
@@ -349,29 +364,31 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadRaw32() throws Exception {
|
public void testReadRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
// 2^15 zero bytes
|
// 2^15 zero bytes
|
||||||
setContents("54" + "00008000" + shortHex);
|
setContents("54" + "00008000" + shortHex);
|
||||||
assertArrayEquals(shortest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(shortest, r.readRaw());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw32ChecksMaxLength() throws Exception {
|
public void testReadRaw32ChecksMaxLength() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
int maxBufferSize = Short.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
byte[] valid = new byte[maxBufferSize];
|
||||||
// 2^15 zero bytes, twice
|
String validHex = toHexString(valid);
|
||||||
setContents("54" + "00008000" + shortHex +
|
String invalidHex = validHex + "00";
|
||||||
"54" + "00008000" + shortHex);
|
// 2^15 zero bytes, 2^15 + 1 zero bytes
|
||||||
assertArrayEquals(shortest, r.readRaw(Short.MAX_VALUE + 1));
|
setContents("54" + "00008000" + validHex +
|
||||||
|
"54" + "00008001" + invalidHex, maxBufferSize);
|
||||||
|
assertArrayEquals(valid, r.readRaw());
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw(Short.MAX_VALUE);
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw32() throws Exception {
|
public void testSkipRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
// 2^15 zero bytes, twice
|
// 2^15 zero bytes, twice
|
||||||
setContents("54" + "00008000" + shortHex +
|
setContents("54" + "00008000" + shortHex +
|
||||||
"54" + "00008000" + shortHex);
|
"54" + "00008000" + shortHex);
|
||||||
@@ -393,6 +410,30 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertEquals(NULL_VALUE, list.get(2));
|
assertEquals(NULL_VALUE, list.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadListChecksMaxLengthForString() throws Exception {
|
||||||
|
// A list containing "foo", a list containing "fooo"
|
||||||
|
setContents("60" + "41" + "03" + "666F6F" + "80"
|
||||||
|
+ "60" + "41" + "04" + "666F6F6F" + "80", 3);
|
||||||
|
BdfList list = r.readList();
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertEquals("foo", list.get(0));
|
||||||
|
assertTrue(r.hasList());
|
||||||
|
r.readList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadListChecksMaxLengthForRaw() throws Exception {
|
||||||
|
// A list containing {1, 2, 3}, a list containing {1, 2, 3, 4}
|
||||||
|
setContents("60" + "51" + "03" + "010203" + "80"
|
||||||
|
+ "60" + "51" + "04" + "01020304" + "80", 3);
|
||||||
|
BdfList list = r.readList();
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertArrayEquals(new byte[] {1, 2, 3}, (byte[]) list.get(0));
|
||||||
|
assertTrue(r.hasList());
|
||||||
|
r.readList();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadListManually() throws Exception {
|
public void testReadListManually() throws Exception {
|
||||||
// A list containing 1, "foo", and null
|
// A list containing 1, "foo", and null
|
||||||
@@ -403,7 +444,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals(1, r.readLong());
|
assertEquals(1, r.readLong());
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals("foo", r.readString(1000));
|
assertEquals("foo", r.readString());
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -435,6 +476,47 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertEquals(NULL_VALUE, dictionary.get("bar"));
|
assertEquals(NULL_VALUE, dictionary.get("bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadDictionaryChecksMaxLengthForKey() throws Exception {
|
||||||
|
// A dictionary containing "foo" -> null, a dictionary containing
|
||||||
|
// "fooo" -> null
|
||||||
|
setContents("70" + "41" + "03" + "666F6F" + "00" + "80"
|
||||||
|
+ "70" + "41" + "04" + "666F6F6F" + "00" + "80", 3);
|
||||||
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
|
assertEquals(1, dictionary.size());
|
||||||
|
assertEquals(NULL_VALUE, dictionary.get("foo"));
|
||||||
|
assertTrue(r.hasDictionary());
|
||||||
|
r.readDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadDictionaryChecksMaxLengthForString() throws Exception {
|
||||||
|
// A dictionary containing "foo" -> "bar", a dictionary containing
|
||||||
|
// "foo" -> "baar"
|
||||||
|
String foo = "41" + "03" + "666F6F";
|
||||||
|
setContents("70" + foo + "41" + "03" + "626172" + "80"
|
||||||
|
+ "70" + foo + "41" + "04" + "62616172" + "80", 3);
|
||||||
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
|
assertEquals(1, dictionary.size());
|
||||||
|
assertEquals("bar", dictionary.get("foo"));
|
||||||
|
assertTrue(r.hasDictionary());
|
||||||
|
r.readDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadDictionaryChecksMaxLengthForRaw() throws Exception {
|
||||||
|
// A dictionary containing "foo" -> {1, 2, 3}, a dictionary containing
|
||||||
|
// "foo" -> {1, 2, 3, 4}
|
||||||
|
String foo = "41" + "03" + "666F6F";
|
||||||
|
setContents("70" + foo + "51" + "03" + "010203" + "80"
|
||||||
|
+ "70" + foo + "51" + "04" + "01020304" + "80", 3);
|
||||||
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
|
assertEquals(1, dictionary.size());
|
||||||
|
assertArrayEquals(new byte[] {1, 2, 3}, (byte[]) dictionary.get("foo"));
|
||||||
|
assertTrue(r.hasDictionary());
|
||||||
|
r.readDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadDictionaryManually() throws Exception {
|
public void testReadDictionaryManually() throws Exception {
|
||||||
// A dictionary containing "foo" -> 123 and "bar" -> null
|
// A dictionary containing "foo" -> 123 and "bar" -> null
|
||||||
@@ -442,11 +524,11 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
"41" + "03" + "626172" + "00" + "80");
|
"41" + "03" + "626172" + "00" + "80");
|
||||||
r.readDictionaryStart();
|
r.readDictionaryStart();
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals("foo", r.readString(1000));
|
assertEquals("foo", r.readString());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals(123, r.readLong());
|
assertEquals(123, r.readLong());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals("bar", r.readString(1000));
|
assertEquals("bar", r.readString());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -537,8 +619,11 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setContents(String hex) {
|
private void setContents(String hex) {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(
|
setContents(hex, DEFAULT_MAX_BUFFER_SIZE);
|
||||||
StringUtils.fromHexString(hex));
|
}
|
||||||
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
|
|
||||||
|
private void setContents(String hex, int maxBufferSize) {
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
|
||||||
|
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,11 +289,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the contact is in the DB (which it's not)
|
// Check whether the contact is in the DB (which it's not)
|
||||||
exactly(17).of(database).startTransaction();
|
exactly(16).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(17).of(database).containsContact(txn, contactId);
|
exactly(16).of(database).containsContact(txn, contactId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(17).of(database).abortTransaction(txn);
|
exactly(16).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -308,16 +308,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
db.endTransaction(transaction);
|
db.endTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
|
||||||
try {
|
|
||||||
db.bindTransportKeys(transaction, contactId, transportId, keySetId);
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchContactException expected) {
|
|
||||||
// Expected
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.generateAck(transaction, contactId, 123);
|
db.generateAck(transaction, contactId, 123);
|
||||||
@@ -773,13 +763,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// endTransaction()
|
// endTransaction()
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
// Check whether the transport is in the DB (which it's not)
|
// Check whether the transport is in the DB (which it's not)
|
||||||
exactly(6).of(database).startTransaction();
|
exactly(5).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(database).containsContact(txn, contactId);
|
exactly(5).of(database).containsTransport(txn, transportId);
|
||||||
will(returnValue(true));
|
|
||||||
exactly(6).of(database).containsTransport(txn, transportId);
|
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(6).of(database).abortTransaction(txn);
|
exactly(5).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -794,16 +782,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
db.endTransaction(transaction);
|
db.endTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
|
||||||
try {
|
|
||||||
db.bindTransportKeys(transaction, contactId, transportId, keySetId);
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchTransportException expected) {
|
|
||||||
// Expected
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.getTransportKeys(transaction, transportId);
|
db.getTransportKeys(transaction, transportId);
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final KeySetId keySetId, keySetId1;
|
private final KeySetId keySetId, keySetId1;
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
JdbcDatabaseTest() throws Exception {
|
JdbcDatabaseTest() throws Exception {
|
||||||
clientId = getClientId();
|
clientId = getClientId();
|
||||||
@@ -670,8 +671,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testTransportKeys() throws Exception {
|
public void testTransportKeys() throws Exception {
|
||||||
long rotationPeriod = 123, rotationPeriod1 = 234;
|
long rotationPeriod = 123, rotationPeriod1 = 234;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
boolean active = random.nextBoolean();
|
||||||
TransportKeys keys1 = createTransportKeys(rotationPeriod1);
|
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
||||||
|
TransportKeys keys1 = createTransportKeys(rotationPeriod1, active);
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -682,7 +684,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
// Add the contact, the transport and the transport keys
|
// Add the contact, the transport and the transport keys
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
true, true));
|
true, active));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
||||||
@@ -701,8 +703,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rotate the transport keys
|
// Rotate the transport keys
|
||||||
TransportKeys rotated = createTransportKeys(rotationPeriod + 1);
|
TransportKeys rotated = createTransportKeys(rotationPeriod + 1, active);
|
||||||
TransportKeys rotated1 = createTransportKeys(rotationPeriod1 + 1);
|
TransportKeys rotated1 =
|
||||||
|
createTransportKeys(rotationPeriod1 + 1, active);
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
||||||
|
|
||||||
@@ -727,95 +730,6 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUnboundTransportKeys() throws Exception {
|
|
||||||
long rotationPeriod = 123, rotationPeriod1 = 234;
|
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
|
||||||
TransportKeys keys1 = createTransportKeys(rotationPeriod1);
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Initially there should be no transport keys in the database
|
|
||||||
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
|
||||||
|
|
||||||
// Add the contact, the transport and the unbound transport keys
|
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
|
||||||
true, true));
|
|
||||||
db.addTransport(txn, transportId, 123);
|
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, null, keys));
|
|
||||||
assertEquals(keySetId1, db.addTransportKeys(txn, null, keys1));
|
|
||||||
|
|
||||||
// Retrieve the transport keys
|
|
||||||
Collection<KeySet> allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (KeySet ks : allKeys) {
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
|
||||||
assertKeysEquals(keys, ks.getTransportKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
|
||||||
assertKeysEquals(keys1, ks.getTransportKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the first set of transport keys
|
|
||||||
db.bindTransportKeys(txn, contactId, transportId, keySetId);
|
|
||||||
|
|
||||||
// Retrieve the keys again - the first set should be bound
|
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (KeySet ks : allKeys) {
|
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertKeysEquals(keys, ks.getTransportKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
assertKeysEquals(keys1, ks.getTransportKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rotate the transport keys
|
|
||||||
TransportKeys rotated = createTransportKeys(rotationPeriod + 1);
|
|
||||||
TransportKeys rotated1 = createTransportKeys(rotationPeriod1 + 1);
|
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId1, null, rotated1));
|
|
||||||
|
|
||||||
// Retrieve the transport keys again
|
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (KeySet ks : allKeys) {
|
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertKeysEquals(rotated, ks.getTransportKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
assertKeysEquals(rotated1, ks.getTransportKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the unbound transport keys
|
|
||||||
db.removeTransportKeys(txn, transportId, keySetId1);
|
|
||||||
|
|
||||||
// Retrieve the keys again - the second set should be gone
|
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(1, allKeys.size());
|
|
||||||
KeySet ks = allKeys.iterator().next();
|
|
||||||
assertEquals(keySetId, ks.getKeySetId());
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertKeysEquals(rotated, ks.getTransportKeys());
|
|
||||||
|
|
||||||
// Removing the transport should remove the remaining transport keys
|
|
||||||
db.removeTransport(txn, transportId);
|
|
||||||
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertKeysEquals(TransportKeys expected,
|
private void assertKeysEquals(TransportKeys expected,
|
||||||
TransportKeys actual) {
|
TransportKeys actual) {
|
||||||
assertEquals(expected.getTransportId(), actual.getTransportId());
|
assertEquals(expected.getTransportId(), actual.getTransportId());
|
||||||
@@ -853,7 +767,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testIncrementStreamCounter() throws Exception {
|
public void testIncrementStreamCounter() throws Exception {
|
||||||
long rotationPeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
TransportKeys keys = createTransportKeys(rotationPeriod, true);
|
||||||
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
@@ -893,8 +807,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetReorderingWindow() throws Exception {
|
public void testSetReorderingWindow() throws Exception {
|
||||||
|
boolean active = random.nextBoolean();
|
||||||
long rotationPeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
||||||
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
||||||
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
||||||
|
|
||||||
@@ -904,12 +819,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
// Add the contact, transport and transport keys
|
// Add the contact, transport and transport keys
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
true, true));
|
true, active));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
|
|
||||||
// Update the reordering window and retrieve the transport keys
|
// Update the reordering window and retrieve the transport keys
|
||||||
new Random().nextBytes(bitmap);
|
random.nextBytes(bitmap);
|
||||||
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
||||||
base + 1, bitmap);
|
base + 1, bitmap);
|
||||||
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
||||||
@@ -1908,7 +1823,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long rotationPeriod) {
|
private TransportKeys createTransportKeys(long rotationPeriod,
|
||||||
|
boolean active) {
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
SecretKey inPrevTagKey = getSecretKey();
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
SecretKey inPrevHeaderKey = getSecretKey();
|
||||||
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
||||||
@@ -1924,7 +1840,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
SecretKey outCurrTagKey = getSecretKey();
|
SecretKey outCurrTagKey = getSecretKey();
|
||||||
SecretKey outCurrHeaderKey = getSecretKey();
|
SecretKey outCurrHeaderKey = getSecretKey();
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
||||||
rotationPeriod, 456, true);
|
rotationPeriod, 456, active);
|
||||||
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
@@ -54,6 +55,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
new StreamContext(contactId, transportId, getSecretKey(),
|
new StreamContext(contactId, transportId, getSecretKey(),
|
||||||
getSecretKey(), 1);
|
getSecretKey(), 1);
|
||||||
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
||||||
pluginConfig, transportKeyManagerFactory);
|
pluginConfig, transportKeyManagerFactory);
|
||||||
@@ -102,30 +104,18 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testAddContact() throws Exception {
|
public void testAddContact() throws Exception {
|
||||||
SecretKey secretKey = getSecretKey();
|
SecretKey secretKey = getSecretKey();
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
boolean alice = new Random().nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
|
boolean active = random.nextBoolean();
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
||||||
timestamp, alice);
|
timestamp, alice, active);
|
||||||
}});
|
|
||||||
|
|
||||||
keyManager.addContact(txn, contactId, secretKey, timestamp, alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddUnboundKeys() throws Exception {
|
|
||||||
SecretKey secretKey = getSecretKey();
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
boolean alice = new Random().nextBoolean();
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(transportKeyManager).addUnboundKeys(txn, secretKey,
|
|
||||||
timestamp, alice);
|
|
||||||
will(returnValue(keySetId));
|
will(returnValue(keySetId));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(singletonMap(transportId, keySetId),
|
Map<TransportId, KeySetId> ids = keyManager.addContact(txn, contactId,
|
||||||
keyManager.addUnboundKeys(txn, secretKey, timestamp, alice));
|
secretKey, timestamp, alice, active);
|
||||||
|
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final ContactId contactId1 = new ContactId(234);
|
private final ContactId contactId1 = new ContactId(234);
|
||||||
private final KeySetId keySetId = new KeySetId(345);
|
private final KeySetId keySetId = new KeySetId(345);
|
||||||
private final KeySetId keySetId1 = new KeySetId(456);
|
private final KeySetId keySetId1 = new KeySetId(456);
|
||||||
private final KeySetId keySetId2 = new KeySetId(567);
|
|
||||||
private final SecretKey tagKey = TestUtils.getSecretKey();
|
private final SecretKey tagKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey headerKey = TestUtils.getSecretKey();
|
private final SecretKey headerKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey masterKey = TestUtils.getSecretKey();
|
private final SecretKey masterKey = TestUtils.getSecretKey();
|
||||||
@@ -71,14 +70,11 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testKeysAreRotatedAtStartup() throws Exception {
|
public void testKeysAreRotatedAtStartup() throws Exception {
|
||||||
TransportKeys shouldRotate = createTransportKeys(900, 0, true);
|
TransportKeys shouldRotate = createTransportKeys(900, 0, true);
|
||||||
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
|
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
|
||||||
TransportKeys shouldRotate1 = createTransportKeys(999, 0, false);
|
|
||||||
Collection<KeySet> loaded = asList(
|
Collection<KeySet> loaded = asList(
|
||||||
new KeySet(keySetId, contactId, shouldRotate),
|
new KeySet(keySetId, contactId, shouldRotate),
|
||||||
new KeySet(keySetId1, contactId1, shouldNotRotate),
|
new KeySet(keySetId1, contactId1, shouldNotRotate)
|
||||||
new KeySet(keySetId2, null, shouldRotate1)
|
|
||||||
);
|
);
|
||||||
TransportKeys rotated = createTransportKeys(1000, 0, true);
|
TransportKeys rotated = createTransportKeys(1000, 0, true);
|
||||||
TransportKeys rotated1 = createTransportKeys(1000, 0, false);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -93,8 +89,6 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(rotated));
|
will(returnValue(rotated));
|
||||||
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
||||||
will(returnValue(shouldNotRotate));
|
will(returnValue(shouldNotRotate));
|
||||||
oneOf(transportCrypto).rotateTransportKeys(shouldRotate1, 1000);
|
|
||||||
will(returnValue(rotated1));
|
|
||||||
// Encode the tags (3 sets per contact)
|
// Encode the tags (3 sets per contact)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(6).of(transportCrypto).encodeTag(
|
exactly(6).of(transportCrypto).encodeTag(
|
||||||
@@ -103,10 +97,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
oneOf(db).updateTransportKeys(txn, asList(
|
oneOf(db).updateTransportKeys(txn,
|
||||||
new KeySet(keySetId, contactId, rotated),
|
singletonList(new KeySet(keySetId, contactId, rotated)));
|
||||||
new KeySet(keySetId2, null, rotated1))
|
|
||||||
);
|
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
||||||
@@ -153,43 +145,11 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is 1 ms before the start of rotation period 1000
|
// The timestamp is 1 ms before the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000 - 1;
|
long timestamp = rotationPeriodLength * 1000 - 1;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreRotatedWhenAddingUnboundKeys() throws Exception {
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
TransportKeys transportKeys = createTransportKeys(999, 0, false);
|
|
||||||
TransportKeys rotated = createTransportKeys(1000, 0, false);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
|
||||||
999, alice, false);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Get the current time (1 ms after start of rotation period 1000)
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(rotationPeriodLength * 1000 + 1));
|
|
||||||
// Rotate the transport keys
|
|
||||||
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
|
||||||
will(returnValue(rotated));
|
|
||||||
// Save the keys
|
|
||||||
oneOf(db).addTransportKeys(txn, null, rotated);
|
|
||||||
will(returnValue(keySetId));
|
|
||||||
}});
|
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
|
||||||
maxLatency);
|
|
||||||
// The timestamp is 1 ms before the start of rotation period 1000
|
|
||||||
long timestamp = rotationPeriodLength * 1000 - 1;
|
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
|
||||||
masterKey, timestamp, alice));
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -211,15 +171,15 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MAX_32_BIT_UNSIGNED + 1, true);
|
MAX_32_BIT_UNSIGNED + 1, true);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, true, transportKeys, txn);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
}
|
}
|
||||||
@@ -232,7 +192,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MAX_32_BIT_UNSIGNED, true);
|
MAX_32_BIT_UNSIGNED, true);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, true, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Increment the stream counter
|
// Increment the stream counter
|
||||||
@@ -244,8 +204,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
// The first request should return a stream context
|
// The first request should return a stream context
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
||||||
@@ -265,19 +225,21 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testIncomingStreamContextIsNullIfTagIsNotFound()
|
public void testIncomingStreamContextIsNullIfTagIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, true);
|
boolean active = random.nextBoolean();
|
||||||
|
TransportKeys transportKeys = createTransportKeys(1000, 0, active);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, active, transportKeys, txn);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, active));
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertEquals(active,
|
||||||
|
transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
// The tag should not be recognised
|
// The tag should not be recognised
|
||||||
assertNull(transportKeyManager.getStreamContext(txn,
|
assertNull(transportKeyManager.getStreamContext(txn,
|
||||||
new byte[TAG_LENGTH]));
|
new byte[TAG_LENGTH]));
|
||||||
@@ -327,8 +289,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
// Use the first tag (previous rotation period, stream number 0)
|
// Use the first tag (previous rotation period, stream number 0)
|
||||||
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
||||||
@@ -415,23 +377,14 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBindingAndActivatingKeys() throws Exception {
|
public void testActivatingKeys() throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, false, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// When the keys are bound, encode the tags (3 sets)
|
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
|
||||||
with(any(byte[].class)), with(tagKey),
|
|
||||||
with(PROTOCOL_VERSION), with(i));
|
|
||||||
will(new EncodeTagAction());
|
|
||||||
}
|
|
||||||
// Save the key binding
|
|
||||||
oneOf(db).bindTransportKeys(txn, contactId, transportId, keySetId);
|
|
||||||
// Activate the keys
|
// Activate the keys
|
||||||
oneOf(db).setTransportKeysActive(txn, transportId, keySetId);
|
oneOf(db).setTransportKeysActive(txn, transportId, keySetId);
|
||||||
// Increment the stream counter
|
// Increment the stream counter
|
||||||
@@ -443,12 +396,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
masterKey, timestamp, alice));
|
masterKey, timestamp, alice, false));
|
||||||
// The keys are unbound so no stream context should be returned
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
|
||||||
transportKeyManager.bindKeys(txn, contactId, keySetId);
|
|
||||||
// The keys are inactive so no stream context should be returned
|
// The keys are inactive so no stream context should be returned
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
@@ -474,18 +423,26 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Keep a copy of the tags
|
// Keep a copy of the tags
|
||||||
List<byte[]> tags = new ArrayList<>();
|
List<byte[]> tags = new ArrayList<>();
|
||||||
|
|
||||||
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// When the keys are bound, encode the tags (3 sets)
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
|
1000, alice, false);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Get the current time (the start of rotation period 1000)
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(rotationPeriodLength * 1000));
|
||||||
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
exactly(3).of(transportCrypto).encodeTag(
|
||||||
with(any(byte[].class)), with(tagKey),
|
with(any(byte[].class)), with(tagKey),
|
||||||
with(PROTOCOL_VERSION), with(i));
|
with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
}
|
}
|
||||||
// Save the key binding
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
oneOf(db).bindTransportKeys(txn, contactId, transportId, keySetId);
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Save the keys
|
||||||
|
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
||||||
|
will(returnValue(keySetId));
|
||||||
// Encode a new tag after sliding the window
|
// Encode a new tag after sliding the window
|
||||||
oneOf(transportCrypto).encodeTag(with(any(byte[].class)),
|
oneOf(transportCrypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(PROTOCOL_VERSION),
|
with(tagKey), with(PROTOCOL_VERSION),
|
||||||
@@ -505,9 +462,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
masterKey, timestamp, alice));
|
masterKey, timestamp, alice, false));
|
||||||
transportKeyManager.bindKeys(txn, contactId, keySetId);
|
|
||||||
// The keys are inactive so no stream context should be returned
|
// The keys are inactive so no stream context should be returned
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
@@ -532,36 +488,11 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(0L, ctx.getStreamNumber());
|
assertEquals(0L, ctx.getStreamNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void expectAddContactNoRotation(boolean alice, boolean active,
|
||||||
public void testRemovingUnboundKeys() throws Exception {
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
|
||||||
|
|
||||||
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
// Remove the unbound keys
|
|
||||||
oneOf(db).removeTransportKeys(txn, transportId, keySetId);
|
|
||||||
}});
|
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
|
||||||
maxLatency);
|
|
||||||
// The timestamp is at the start of rotation period 1000
|
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
|
||||||
masterKey, timestamp, alice));
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
transportKeyManager.removeKeys(txn, keySetId);
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void expectAddContactNoRotation(boolean alice,
|
|
||||||
TransportKeys transportKeys, Transaction txn) throws Exception {
|
TransportKeys transportKeys, Transaction txn) throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
1000, alice, true);
|
1000, alice, active);
|
||||||
will(returnValue(transportKeys));
|
will(returnValue(transportKeys));
|
||||||
// Get the current time (the start of rotation period 1000)
|
// Get the current time (the start of rotation period 1000)
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
@@ -582,24 +513,6 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectAddUnboundKeysNoRotation(boolean alice,
|
|
||||||
TransportKeys transportKeys, Transaction txn) throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
|
||||||
1000, alice, false);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Get the current time (the start of rotation period 1000)
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(rotationPeriodLength * 1000));
|
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
|
||||||
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Save the unbound keys
|
|
||||||
oneOf(db).addTransportKeys(txn, null, transportKeys);
|
|
||||||
will(returnValue(keySetId));
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long rotationPeriod,
|
private TransportKeys createTransportKeys(long rotationPeriod,
|
||||||
long streamCounter, boolean active) {
|
long streamCounter, boolean active) {
|
||||||
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
||||||
|
|||||||
@@ -218,16 +218,16 @@ dependencyVerification {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def getGitHash = { ->
|
def getStdout = { command, defaultValue ->
|
||||||
def stdout = new ByteArrayOutputStream()
|
def stdout = new ByteArrayOutputStream()
|
||||||
try {
|
try {
|
||||||
exec {
|
exec {
|
||||||
commandLine 'git', 'rev-parse', '--short=7', 'HEAD'
|
commandLine = command
|
||||||
standardOutput = stdout
|
standardOutput = stdout
|
||||||
}
|
}
|
||||||
return stdout.toString().trim()
|
return stdout.toString().trim()
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return "No commit hash"
|
return defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,13 +238,15 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10003
|
versionCode 10004
|
||||||
versionName "1.0.3"
|
versionName "1.0.4"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
resValue "string", "app_package", "org.briarproject.briar.android"
|
resValue "string", "app_package", "org.briarproject.briar.android"
|
||||||
resValue "string", "app_name", "Briar"
|
resValue "string", "app_name", "Briar"
|
||||||
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
buildConfigField "String", "GitHash",
|
||||||
buildConfigField "Long", "BuildTimestamp", "${System.currentTimeMillis()}L"
|
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""
|
||||||
|
buildConfigField "Long", "BuildTimestamp",
|
||||||
|
"${getStdout(['git', 'log', '-n', '1', '--date=unix', '--format=%cd'], 0)}000L"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_LOGS"/>
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.StrictMode;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
@@ -13,6 +14,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.ui.UiCallback;
|
import org.briarproject.bramble.api.ui.UiCallback;
|
||||||
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
@@ -82,7 +84,11 @@ public class AppModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
DatabaseConfig provideDatabaseConfig(Application app) {
|
DatabaseConfig provideDatabaseConfig(Application app) {
|
||||||
|
//FIXME: StrictMode
|
||||||
|
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskReads();
|
||||||
|
StrictMode.allowThreadDiskWrites();
|
||||||
File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||||
|
StrictMode.setThreadPolicy(tp);
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
DatabaseConfig databaseConfig = new AndroidDatabaseConfig(dir);
|
DatabaseConfig databaseConfig = new AndroidDatabaseConfig(dir);
|
||||||
@@ -91,7 +97,7 @@ public class AppModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
DevConfig provideDevConfig(CryptoComponent crypto) {
|
DevConfig provideDevConfig(Application app, CryptoComponent crypto) {
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
DevConfig devConfig = new DevConfig() {
|
DevConfig devConfig = new DevConfig() {
|
||||||
|
|
||||||
@@ -109,6 +115,11 @@ public class AppModule {
|
|||||||
public String getDevOnionAddress() {
|
public String getDevOnionAddress() {
|
||||||
return DEV_ONION_ADDRESS;
|
return DEV_ONION_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getReportDir() {
|
||||||
|
return AndroidUtils.getReportDir(app.getApplicationContext());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return devConfig;
|
return devConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This exists so that the Application object will not necessarily be cast
|
* This exists so that the Application object will not necessarily be cast
|
||||||
* directly to the Briar application object.
|
* directly to the Briar application object.
|
||||||
*/
|
*/
|
||||||
public interface BriarApplication {
|
public interface BriarApplication {
|
||||||
|
|
||||||
|
Collection<LogRecord> getRecentLogRecords();
|
||||||
|
|
||||||
AndroidComponent getApplicationComponent();
|
AndroidComponent getApplicationComponent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,17 @@ import org.acra.annotation.ReportsCrashes;
|
|||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.logging.CachingLogHandler;
|
||||||
import org.briarproject.briar.android.reporting.BriarReportPrimer;
|
import org.briarproject.briar.android.reporting.BriarReportPrimer;
|
||||||
import org.briarproject.briar.android.reporting.BriarReportSenderFactory;
|
import org.briarproject.briar.android.reporting.BriarReportSenderFactory;
|
||||||
import org.briarproject.briar.android.reporting.DevReportActivity;
|
import org.briarproject.briar.android.reporting.DevReportActivity;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static org.acra.ReportField.ANDROID_VERSION;
|
import static org.acra.ReportField.ANDROID_VERSION;
|
||||||
import static org.acra.ReportField.APP_VERSION_CODE;
|
import static org.acra.ReportField.APP_VERSION_CODE;
|
||||||
import static org.acra.ReportField.APP_VERSION_NAME;
|
import static org.acra.ReportField.APP_VERSION_NAME;
|
||||||
@@ -28,7 +33,6 @@ import static org.acra.ReportField.CUSTOM_DATA;
|
|||||||
import static org.acra.ReportField.DEVICE_FEATURES;
|
import static org.acra.ReportField.DEVICE_FEATURES;
|
||||||
import static org.acra.ReportField.DISPLAY;
|
import static org.acra.ReportField.DISPLAY;
|
||||||
import static org.acra.ReportField.INITIAL_CONFIGURATION;
|
import static org.acra.ReportField.INITIAL_CONFIGURATION;
|
||||||
import static org.acra.ReportField.LOGCAT;
|
|
||||||
import static org.acra.ReportField.PACKAGE_NAME;
|
import static org.acra.ReportField.PACKAGE_NAME;
|
||||||
import static org.acra.ReportField.PHONE_MODEL;
|
import static org.acra.ReportField.PHONE_MODEL;
|
||||||
import static org.acra.ReportField.PRODUCT;
|
import static org.acra.ReportField.PRODUCT;
|
||||||
@@ -36,7 +40,7 @@ import static org.acra.ReportField.REPORT_ID;
|
|||||||
import static org.acra.ReportField.STACK_TRACE;
|
import static org.acra.ReportField.STACK_TRACE;
|
||||||
import static org.acra.ReportField.USER_APP_START_DATE;
|
import static org.acra.ReportField.USER_APP_START_DATE;
|
||||||
import static org.acra.ReportField.USER_CRASH_DATE;
|
import static org.acra.ReportField.USER_CRASH_DATE;
|
||||||
import static org.briarproject.briar.android.TestingConstants.DEFAULT_LOG_LEVEL;
|
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.TestingConstants.IS_DEBUG_BUILD;
|
||||||
|
|
||||||
@ReportsCrashes(
|
@ReportsCrashes(
|
||||||
@@ -56,8 +60,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
|||||||
STACK_TRACE,
|
STACK_TRACE,
|
||||||
INITIAL_CONFIGURATION, CRASH_CONFIGURATION,
|
INITIAL_CONFIGURATION, CRASH_CONFIGURATION,
|
||||||
DISPLAY, DEVICE_FEATURES,
|
DISPLAY, DEVICE_FEATURES,
|
||||||
USER_APP_START_DATE, USER_CRASH_DATE,
|
USER_APP_START_DATE, USER_CRASH_DATE
|
||||||
LOGCAT
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public class BriarApplicationImpl extends Application
|
public class BriarApplicationImpl extends Application
|
||||||
@@ -66,6 +69,8 @@ public class BriarApplicationImpl extends Application
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BriarApplicationImpl.class.getName());
|
Logger.getLogger(BriarApplicationImpl.class.getName());
|
||||||
|
|
||||||
|
private final CachingLogHandler logHandler = new CachingLogHandler();
|
||||||
|
|
||||||
private AndroidComponent applicationComponent;
|
private AndroidComponent applicationComponent;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -79,7 +84,17 @@ public class BriarApplicationImpl extends Application
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
if (IS_DEBUG_BUILD) enableStrictMode();
|
if (IS_DEBUG_BUILD) enableStrictMode();
|
||||||
Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
|
|
||||||
|
Logger rootLogger = Logger.getLogger("");
|
||||||
|
if (!IS_DEBUG_BUILD && !IS_BETA_BUILD) {
|
||||||
|
// Remove default log handlers so system log is not used
|
||||||
|
for (Handler handler : rootLogger.getHandlers()) {
|
||||||
|
rootLogger.removeHandler(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rootLogger.addHandler(logHandler);
|
||||||
|
rootLogger.setLevel(INFO);
|
||||||
|
|
||||||
LOG.info("Created");
|
LOG.info("Created");
|
||||||
|
|
||||||
applicationComponent = DaggerAndroidComponent.builder()
|
applicationComponent = DaggerAndroidComponent.builder()
|
||||||
@@ -104,6 +119,11 @@ public class BriarApplicationImpl extends Application
|
|||||||
StrictMode.setVmPolicy(vmPolicy.build());
|
StrictMode.setVmPolicy(vmPolicy.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<LogRecord> getRecentLogRecords() {
|
||||||
|
return logHandler.getRecentLogRecords();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AndroidComponent getApplicationComponent() {
|
public AndroidComponent getApplicationComponent() {
|
||||||
return applicationComponent;
|
return applicationComponent;
|
||||||
|
|||||||
@@ -2,11 +2,6 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import org.briarproject.briar.BuildConfig;
|
import org.briarproject.briar.BuildConfig;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Level.OFF;
|
|
||||||
|
|
||||||
public interface TestingConstants {
|
public interface TestingConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,12 +15,6 @@ public interface TestingConstants {
|
|||||||
*/
|
*/
|
||||||
boolean IS_BETA_BUILD = false;
|
boolean IS_BETA_BUILD = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Default log level. Disable logging for final release builds.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
Level DEFAULT_LOG_LEVEL = IS_DEBUG_BUILD || IS_BETA_BUILD ? INFO : OFF;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to prevent screenshots from being taken. Setting this to true
|
* Whether to prevent screenshots from being taken. Setting this to true
|
||||||
* prevents Recent Apps from storing screenshots of private information.
|
* prevents Recent Apps from storing screenshots of private information.
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.briarproject.briar.android.logging;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Locale.US;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class BriefLogFormatter extends Formatter {
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private final DateFormat dateFormat; // Locking: lock
|
||||||
|
private final Date date; // Locking: lock
|
||||||
|
|
||||||
|
public BriefLogFormatter() {
|
||||||
|
synchronized (lock) {
|
||||||
|
dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ", US);
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
date = new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(LogRecord record) {
|
||||||
|
String dateString;
|
||||||
|
synchronized (lock) {
|
||||||
|
date.setTime(record.getMillis());
|
||||||
|
dateString = dateFormat.format(date);
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder(dateString);
|
||||||
|
sb.append(record.getLevel().getName().charAt(0)).append('/');
|
||||||
|
String tag = record.getLoggerName();
|
||||||
|
tag = tag.substring(tag.lastIndexOf('.') + 1);
|
||||||
|
sb.append(tag).append(": ");
|
||||||
|
sb.append(record.getMessage());
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.briarproject.briar.android.logging;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class CachingLogHandler extends Handler {
|
||||||
|
|
||||||
|
private static final int MAX_RECENT_RECORDS = 100;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
// Locking: lock
|
||||||
|
private final Queue<LogRecord> recent = new LinkedList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(LogRecord record) {
|
||||||
|
synchronized (lock) {
|
||||||
|
recent.add(record);
|
||||||
|
if (recent.size() > MAX_RECENT_RECORDS) recent.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
synchronized (lock) {
|
||||||
|
recent.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<LogRecord> getRecentLogRecords() {
|
||||||
|
synchronized (lock) {
|
||||||
|
return new ArrayList<>(recent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,8 @@ import org.acra.builder.ReportBuilder;
|
|||||||
import org.acra.builder.ReportPrimer;
|
import org.acra.builder.ReportPrimer;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.BuildConfig;
|
import org.briarproject.briar.BuildConfig;
|
||||||
|
import org.briarproject.briar.android.BriarApplication;
|
||||||
|
import org.briarproject.briar.android.logging.BriefLogFormatter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -28,6 +30,8 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
|
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
|
||||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
||||||
@@ -69,6 +73,16 @@ public class BriarReportPrimer implements ReportPrimer {
|
|||||||
public Map<String, String> call() {
|
public Map<String, String> call() {
|
||||||
Map<String, String> customData = new LinkedHashMap<>();
|
Map<String, String> customData = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// Log
|
||||||
|
BriarApplication app =
|
||||||
|
(BriarApplication) ctx.getApplicationContext();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Formatter formatter = new BriefLogFormatter();
|
||||||
|
for (LogRecord record : app.getRecentLogRecords()) {
|
||||||
|
sb.append(formatter.format(record)).append('\n');
|
||||||
|
}
|
||||||
|
customData.put("Log", sb.toString());
|
||||||
|
|
||||||
// System memory
|
// System memory
|
||||||
Object o = ctx.getSystemService(ACTIVITY_SERVICE);
|
Object o = ctx.getSystemService(ACTIVITY_SERVICE);
|
||||||
ActivityManager am = (ActivityManager) o;
|
ActivityManager am = (ActivityManager) o;
|
||||||
@@ -223,9 +237,10 @@ public class BriarReportPrimer implements ReportPrimer {
|
|||||||
customData.put("Bluetooth LE status", btLeStatus);
|
customData.put("Bluetooth LE status", btLeStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt != null)
|
if (bt != null) {
|
||||||
customData.put("Bluetooth address",
|
customData.put("Bluetooth address",
|
||||||
scrubMacAddress(bt.getAddress()));
|
scrubMacAddress(bt.getAddress()));
|
||||||
|
}
|
||||||
String btSettingsAddr;
|
String btSettingsAddr;
|
||||||
try {
|
try {
|
||||||
btSettingsAddr = Settings.Secure.getString(
|
btSettingsAddr = Settings.Secure.getString(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import android.support.annotation.NonNull;
|
|||||||
import org.acra.collector.CrashReportData;
|
import org.acra.collector.CrashReportData;
|
||||||
import org.acra.sender.ReportSender;
|
import org.acra.sender.ReportSender;
|
||||||
import org.acra.sender.ReportSenderException;
|
import org.acra.sender.ReportSenderException;
|
||||||
import org.acra.util.JSONReportBuilder;
|
import org.acra.util.JSONReportBuilder.JSONReportException;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.briar.android.AndroidComponent;
|
import org.briarproject.briar.android.AndroidComponent;
|
||||||
@@ -37,7 +37,7 @@ public class BriarReportSender implements ReportSender {
|
|||||||
String crashReport;
|
String crashReport;
|
||||||
try {
|
try {
|
||||||
crashReport = errorContent.toJSON().toString();
|
crashReport = errorContent.toJSON().toString();
|
||||||
} catch (JSONReportBuilder.JSONReportException e) {
|
} catch (JSONReportException e) {
|
||||||
throw new ReportSenderException("Couldn't create JSON", e);
|
throw new ReportSenderException("Couldn't create JSON", e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import android.support.v7.preference.CheckBoxPreference;
|
|||||||
import android.support.v7.preference.ListPreference;
|
import android.support.v7.preference.ListPreference;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||||
|
import android.support.v7.preference.PreferenceGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.acra.ACRA;
|
import org.acra.ACRA;
|
||||||
@@ -149,9 +150,19 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
Preference testData = findPreference("pref_key_test_data");
|
if (IS_DEBUG_BUILD) {
|
||||||
if (!IS_DEBUG_BUILD) {
|
findPreference("pref_key_explode").setOnPreferenceClickListener(
|
||||||
testData.setVisible(false);
|
preference -> {
|
||||||
|
throw new RuntimeException("Boom!");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
findPreference("pref_key_explode").setVisible(false);
|
||||||
|
findPreference("pref_key_test_data").setVisible(false);
|
||||||
|
PreferenceGroup testing =
|
||||||
|
findPreference("pref_key_explode").getParent();
|
||||||
|
if (testing == null) throw new AssertionError();
|
||||||
|
testing.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="@color/divider">
|
|
||||||
</View>
|
|
||||||
11
briar-android/src/main/res/layout/preferences_category.xml
Normal file
11
briar-android/src/main/res/layout/preferences_category.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@android:id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/briar_blue_light"/>
|
||||||
147
briar-android/src/main/res/values-ast/strings.xml
Normal file
147
briar-android/src/main/res/values-ast/strings.xml
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<resources>
|
||||||
|
<!--Setup-->
|
||||||
|
<string name="setup_title">Afáyate\'n Briar</string>
|
||||||
|
<string name="setup_name_explanation">El to alcuñu apaecerá cabo cualquier conteníu que publiques.Nun puede cambiase después de crear la cuenta.</string>
|
||||||
|
<string name="setup_next">Siguiente</string>
|
||||||
|
<string name="setup_password_intro">Escueye una contraseña</string>
|
||||||
|
<string name="setup_doze_title">Conexones de fondu</string>
|
||||||
|
<string name="setup_doze_button">Permitir conexones</string>
|
||||||
|
<string name="choose_nickname">Escueyi un alcuñu</string>
|
||||||
|
<string name="choose_password">Escueyi una contraseña</string>
|
||||||
|
<string name="confirm_password">Confirma la contraseña</string>
|
||||||
|
<string name="name_too_long">El nome ye enforma llargu</string>
|
||||||
|
<string name="password_too_weak">La contraseña ye enforma feble</string>
|
||||||
|
<string name="passwords_do_not_match">Les contraseñes nun casen</string>
|
||||||
|
<string name="create_account_button">Crear cuenta</string>
|
||||||
|
<string name="more_info">Más información</string>
|
||||||
|
<string name="don_t_ask_again">Nun volver a entrugar</string>
|
||||||
|
<string name="setup_huawei_button">Protexer Briar</string>
|
||||||
|
<string name="warning_dozed">%s nun pudo executase\'n segundu planu</string>
|
||||||
|
<!--Login-->
|
||||||
|
<string name="enter_password">Escribi la contraseña</string>
|
||||||
|
<string name="try_again">Contraseña enquivocada, tenta otra vuelta</string>
|
||||||
|
<string name="sign_in_button">Aniciar sesión</string>
|
||||||
|
<string name="forgotten_password">Escaecí la contraseña</string>
|
||||||
|
<string name="dialog_title_lost_password">Contraseña perdida</string>
|
||||||
|
<string name="dialog_message_lost_password">La cuenta de Briar guárdase cifrada nel preséu, non na nube, de manera que nun podemos reaniciala.. ¿Quies desaniciar la cuenta y principiar de cero?\n\nAtención: Les tos identidaes, contautos y mensaxes perderánse de mou permanente.</string>
|
||||||
|
<string name="startup_failed_notification_title">Briar nun pudo arrancar</string>
|
||||||
|
<string name="startup_failed_activity_title">Fallu nel arranque de Briar</string>
|
||||||
|
<string name="expiry_date_reached">Esti software caducó.\n¡Gracies por probalu!</string>
|
||||||
|
<string name="download_briar">Pa siguir usando Briar, descarga la versión 1.0.</string>
|
||||||
|
<string name="create_new_account">Tendrás de crear una cuenta nueva, pero puedes usar el mesmu alcuñu.</string>
|
||||||
|
<string name="download_briar_button">Descargar Briar 1.0</string>
|
||||||
|
<!--Navigation Drawer-->
|
||||||
|
<string name="nav_drawer_open_description">Abrir el caxón de navegación</string>
|
||||||
|
<string name="nav_drawer_close_description">Zarrar el caxón de navegación</string>
|
||||||
|
<string name="contact_list_button">Contactos</string>
|
||||||
|
<string name="groups_button">Grupos privaos</string>
|
||||||
|
<string name="forums_button">Foros</string>
|
||||||
|
<string name="blogs_button">Blogs</string>
|
||||||
|
<string name="settings_button">Preferencies</string>
|
||||||
|
<string name="sign_out_button">Colar</string>
|
||||||
|
<!--Transports-->
|
||||||
|
<string name="transport_tor">Internet</string>
|
||||||
|
<string name="transport_bt">Bluetooth</string>
|
||||||
|
<string name="transport_lan">Wi-Fi</string>
|
||||||
|
<!--Notifications-->
|
||||||
|
<string name="ongoing_notification_title">Sesión aniciada</string>
|
||||||
|
<string name="ongoing_notification_text">Toca p\'abrir Briar.</string>
|
||||||
|
<plurals name="private_message_notification_text">
|
||||||
|
<item quantity="one">Mensaxes priváu nuevu.</item>
|
||||||
|
<item quantity="other">%d mensaxes privaos nuevos.</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="group_message_notification_text">
|
||||||
|
<item quantity="one">Mensaxe de grupu nuevu.</item>
|
||||||
|
<item quantity="other">%d mensaxes de grupu nuevos.</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="forum_post_notification_text">
|
||||||
|
<item quantity="one">Mensaxe de foru nuevu.</item>
|
||||||
|
<item quantity="other">%d mensaxes de foru nuevos.</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="blog_post_notification_text">
|
||||||
|
<item quantity="one">Una publicación del blog nueva.</item>
|
||||||
|
<item quantity="other">%d publicaciones del blog nueves.</item>
|
||||||
|
</plurals>
|
||||||
|
<!--Misc-->
|
||||||
|
<string name="now">agora</string>
|
||||||
|
<string name="show">Amosar</string>
|
||||||
|
<string name="hide">Anubrir</string>
|
||||||
|
<string name="ok">Aceutar</string>
|
||||||
|
<string name="cancel">Encaboxar</string>
|
||||||
|
<string name="got_it">Entendílo</string>
|
||||||
|
<string name="delete">Desaniciar</string>
|
||||||
|
<string name="accept">Aceutar</string>
|
||||||
|
<string name="decline">Refugar</string>
|
||||||
|
<string name="options">Opciones</string>
|
||||||
|
<string name="online">En llinia</string>
|
||||||
|
<string name="offline">Sin conexón</string>
|
||||||
|
<string name="send">Unviar</string>
|
||||||
|
<string name="allow">Permitir</string>
|
||||||
|
<string name="open">Abrir</string>
|
||||||
|
<string name="no_data">Sin datos</string>
|
||||||
|
<string name="ellipsis">…</string>
|
||||||
|
<string name="fix">Iguar</string>
|
||||||
|
<string name="help">Ayuda</string>
|
||||||
|
<!--Contacts and Private Conversations-->
|
||||||
|
<!--Adding Contacts-->
|
||||||
|
<!--Introductions-->
|
||||||
|
<!--Private Groups-->
|
||||||
|
<plurals name="messages">
|
||||||
|
<item quantity="one">%d mensaxe</item>
|
||||||
|
<item quantity="other">%d mensaxes</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="groups_remove">Desaniciar</string>
|
||||||
|
<string name="groups_create_group_title">Crear Grupu priváu</string>
|
||||||
|
<string name="groups_create_group_button">Crear Grupu</string>
|
||||||
|
<string name="groups_create_group_invitation_button">Unviar Invitación</string>
|
||||||
|
<string name="groups_member_list">Llista de miembros</string>
|
||||||
|
<string name="groups_invite_members">Invitar a miembros</string>
|
||||||
|
<string name="groups_member_created_you">Creasti\'\'l grupu</string>
|
||||||
|
<string name="groups_member_created">%s creó\'\'l grupu</string>
|
||||||
|
<string name="groups_dissolve_button">Disolver</string>
|
||||||
|
<string name="groups_dissolved_dialog_title">Disolvióse\'\'l grupu</string>
|
||||||
|
<!--Private Group Invitations-->
|
||||||
|
<string name="groups_invitations_invitation_sent">Invitasti a %1$s a xunise al grupu \"%2$s\".</string>
|
||||||
|
<string name="groups_invitations_invitation_received">%1$s invitóte a xunite al grupu \"%2$s\".</string>
|
||||||
|
<!--Private Groups Revealing Contacts-->
|
||||||
|
<!--Forums-->
|
||||||
|
<string name="create_forum_title">Crear foru</string>
|
||||||
|
<string name="choose_forum_hint">Escueyi un nome pal foru</string>
|
||||||
|
<string name="create_forum_button">Crear foru</string>
|
||||||
|
<string name="forum_created_toast">Creóse\'l foru</string>
|
||||||
|
<string name="no_forum_posts">Nun hai mensaxes qu\'amosar</string>
|
||||||
|
<!--Forum Sharing-->
|
||||||
|
<string name="nobody">Naide</string>
|
||||||
|
<!--Blogs-->
|
||||||
|
<string name="blogs_other_blog_empty_state">Nun hai mensaxes qu\'amosar</string>
|
||||||
|
<string name="read_more">lleer más</string>
|
||||||
|
<string name="blogs_publish_blog_post">Publicar</string>
|
||||||
|
<string name="blogs_remove_blog_ok">Desaniciar</string>
|
||||||
|
<!--Blog Sharing-->
|
||||||
|
<!--RSS Feeds-->
|
||||||
|
<string name="blogs_rss_feeds_import">Importar canal RSS</string>
|
||||||
|
<string name="blogs_rss_feeds_import_button">Importar</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_author">Autor:</string>
|
||||||
|
<string name="blogs_rss_remove_feed_ok">Desaniciar</string>
|
||||||
|
<!--Settings Network-->
|
||||||
|
<string name="network_settings_title">Redes</string>
|
||||||
|
<string name="tor_network_setting">Coneutar vía Tor</string>
|
||||||
|
<string name="tor_network_setting_never">Nunca</string>
|
||||||
|
<string name="tor_network_setting_wifi">Sólo al usar Wi-Fi</string>
|
||||||
|
<!--Settings Security and Panic-->
|
||||||
|
<string name="security_settings_title">Seguridá</string>
|
||||||
|
<string name="panic_setting">Configuración del Botón d\'espantu</string>
|
||||||
|
<string name="panic_setting_title">Botón d\'espantu</string>
|
||||||
|
<string name="lock_setting_title">Colar</string>
|
||||||
|
<string name="uninstall_setting_title">Desinstalar Briar</string>
|
||||||
|
<!--Settings Notifications-->
|
||||||
|
<string name="notification_settings_title">Avisos</string>
|
||||||
|
<string name="notify_private_messages_setting_title">Mensaxes privaos</string>
|
||||||
|
<!--Settings Feedback-->
|
||||||
|
<!--Link Warning-->
|
||||||
|
<!--Crash Reporter-->
|
||||||
|
<!--Sign Out-->
|
||||||
|
<!--Screen Filters & Tapjacking-->
|
||||||
|
<!--Permission Requests-->
|
||||||
|
</resources>
|
||||||
@@ -326,5 +326,4 @@
|
|||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Открит е овърлей на екрана</string>
|
<string name="screen_filter_title">Открит е овърлей на екрана</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -39,18 +39,30 @@
|
|||||||
<string name="ongoing_notification_text">Touchit da zigeriñ Briar.</string>
|
<string name="ongoing_notification_text">Touchit da zigeriñ Briar.</string>
|
||||||
<plurals name="private_message_notification_text">
|
<plurals name="private_message_notification_text">
|
||||||
<item quantity="one">Kemennadenn prevez nevez</item>
|
<item quantity="one">Kemennadenn prevez nevez</item>
|
||||||
|
<item quantity="two">%d a gemennadennoù prevez nevez. </item>
|
||||||
|
<item quantity="few">%d a gemennadennoù prevez nevez. </item>
|
||||||
|
<item quantity="many">%d a gemennadennoù prevez nevez. </item>
|
||||||
<item quantity="other">%d a gemennadennoù prevez nevez. </item>
|
<item quantity="other">%d a gemennadennoù prevez nevez. </item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="group_message_notification_text">
|
<plurals name="group_message_notification_text">
|
||||||
<item quantity="one">Kemennadenn strollad nevez.</item>
|
<item quantity="one">Kemennadenn strollad nevez.</item>
|
||||||
|
<item quantity="two">%d a gemennadennoù strollad nevez.</item>
|
||||||
|
<item quantity="few">%d a gemennadennoù strollad nevez.</item>
|
||||||
|
<item quantity="many">%d a gemennadennoù strollad nevez.</item>
|
||||||
<item quantity="other">%d a gemennadennoù strollad nevez.</item>
|
<item quantity="other">%d a gemennadennoù strollad nevez.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="forum_post_notification_text">
|
<plurals name="forum_post_notification_text">
|
||||||
<item quantity="one">Postadenn forom nevez.</item>
|
<item quantity="one">Postadenn forom nevez.</item>
|
||||||
|
<item quantity="two">%da bostadennoù forom nevez.</item>
|
||||||
|
<item quantity="few">%da bostadennoù forom nevez.</item>
|
||||||
|
<item quantity="many">%da bostadennoù forom nevez.</item>
|
||||||
<item quantity="other">%da bostadennoù forom nevez.</item>
|
<item quantity="other">%da bostadennoù forom nevez.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="blog_post_notification_text">
|
<plurals name="blog_post_notification_text">
|
||||||
<item quantity="one">Postadenn blog nevez.</item>
|
<item quantity="one">Postadenn blog nevez.</item>
|
||||||
|
<item quantity="two">%d a bostadennoù blog nevez.</item>
|
||||||
|
<item quantity="few">%d a bostadennoù blog nevez.</item>
|
||||||
|
<item quantity="many">%d a bostadennoù blog nevez.</item>
|
||||||
<item quantity="other">%d a bostadennoù blog nevez.</item>
|
<item quantity="other">%d a bostadennoù blog nevez.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Misc-->
|
<!--Misc-->
|
||||||
@@ -99,12 +111,18 @@
|
|||||||
<string name="introduction_response_error">Fazi en ur respont d\'an digoradur</string>
|
<string name="introduction_response_error">Fazi en ur respont d\'an digoradur</string>
|
||||||
<plurals name="introduction_notification_text">
|
<plurals name="introduction_notification_text">
|
||||||
<item quantity="one">Darempred nevez ouzhpennet.</item>
|
<item quantity="one">Darempred nevez ouzhpennet.</item>
|
||||||
|
<item quantity="two">%d a zarempredoù nevez ouzhpennet.</item>
|
||||||
|
<item quantity="few">%d a zarempredoù nevez ouzhpennet.</item>
|
||||||
|
<item quantity="many">%d a zarempredoù nevez ouzhpennet.</item>
|
||||||
<item quantity="other">%d a zarempredoù nevez ouzhpennet.</item>
|
<item quantity="other">%d a zarempredoù nevez ouzhpennet.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
<string name="groups_created_by">Graet gant %s</string>
|
<string name="groups_created_by">Graet gant %s</string>
|
||||||
<plurals name="messages">
|
<plurals name="messages">
|
||||||
<item quantity="one">%d kemennadenn</item>
|
<item quantity="one">%d kemennadenn</item>
|
||||||
|
<item quantity="two">%d a gemennadennoù</item>
|
||||||
|
<item quantity="few">%d a gemennadennoù</item>
|
||||||
|
<item quantity="many">%d a gemennadennoù</item>
|
||||||
<item quantity="other">%d a gemennadennoù</item>
|
<item quantity="other">%d a gemennadennoù</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_group_is_empty">Leun eo ar strollad-mañ</string>
|
<string name="groups_group_is_empty">Leun eo ar strollad-mañ</string>
|
||||||
@@ -149,5 +167,4 @@
|
|||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -393,7 +393,4 @@
|
|||||||
<string name="permission_camera_denied_toast">No s\'ha concedit el permís de la càmera</string>
|
<string name="permission_camera_denied_toast">No s\'ha concedit el permís de la càmera</string>
|
||||||
<string name="qr_code">Codi QR</string>
|
<string name="qr_code">Codi QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Mostra el codi QR a pantalla completa</string>
|
<string name="show_qr_code_fullscreen">Mostra el codi QR a pantalla completa</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Has sortit de Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Has sortit de Briar a causa de falta de memòria.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
<item quantity="one">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
||||||
<item quantity="few">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
<item quantity="few">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
||||||
|
<item quantity="many">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
||||||
<item quantity="other">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
<item quantity="other">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_update">Datum expirace pro testování bylo prodlouženo. Váš účet nyní bude expirovat po %d dnech.</string>
|
<string name="expiry_update">Datum expirace pro testování bylo prodlouženo. Váš účet nyní bude expirovat po %d dnech.</string>
|
||||||
@@ -59,21 +60,25 @@
|
|||||||
<plurals name="private_message_notification_text">
|
<plurals name="private_message_notification_text">
|
||||||
<item quantity="one">Nová soukromá zpráva</item>
|
<item quantity="one">Nová soukromá zpráva</item>
|
||||||
<item quantity="few">%d nových soukromých zpráv.</item>
|
<item quantity="few">%d nových soukromých zpráv.</item>
|
||||||
|
<item quantity="many">%d nových soukromých zpráv.</item>
|
||||||
<item quantity="other">%d nových soukromých zpráv.</item>
|
<item quantity="other">%d nových soukromých zpráv.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="group_message_notification_text">
|
<plurals name="group_message_notification_text">
|
||||||
<item quantity="one">Nová zpráva ve skupině.</item>
|
<item quantity="one">Nová zpráva ve skupině.</item>
|
||||||
<item quantity="few">%d nových zpráv ve skupině. </item>
|
<item quantity="few">%d nových zpráv ve skupině. </item>
|
||||||
|
<item quantity="many">%d nových zpráv ve skupině.</item>
|
||||||
<item quantity="other">%d nových zpráv ve skupině.</item>
|
<item quantity="other">%d nových zpráv ve skupině.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="forum_post_notification_text">
|
<plurals name="forum_post_notification_text">
|
||||||
<item quantity="one">Nový příspěvek ve fóru.</item>
|
<item quantity="one">Nový příspěvek ve fóru.</item>
|
||||||
<item quantity="few">%dnových příspěvků ve fóru. </item>
|
<item quantity="few">%dnových příspěvků ve fóru. </item>
|
||||||
|
<item quantity="many">%d nových příspěvků ve fóru.</item>
|
||||||
<item quantity="other">%d nových příspěvků ve fóru.</item>
|
<item quantity="other">%d nových příspěvků ve fóru.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="blog_post_notification_text">
|
<plurals name="blog_post_notification_text">
|
||||||
<item quantity="one">Nový příspěvek v blogu.</item>
|
<item quantity="one">Nový příspěvek v blogu.</item>
|
||||||
<item quantity="few">%dnových příspěvků v blogu. </item>
|
<item quantity="few">%dnových příspěvků v blogu. </item>
|
||||||
|
<item quantity="many">%d nových příspěvků v blogu.</item>
|
||||||
<item quantity="other">%d nových příspěvků v blogu.</item>
|
<item quantity="other">%d nových příspěvků v blogu.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Misc-->
|
<!--Misc-->
|
||||||
@@ -144,6 +149,7 @@
|
|||||||
<plurals name="introduction_notification_text">
|
<plurals name="introduction_notification_text">
|
||||||
<item quantity="one">Nový kontakt byl přidán.</item>
|
<item quantity="one">Nový kontakt byl přidán.</item>
|
||||||
<item quantity="few">Bylo přidáno %d nových kontaktů.</item>
|
<item quantity="few">Bylo přidáno %d nových kontaktů.</item>
|
||||||
|
<item quantity="many">%d nových kontaktů bylo přidáno.</item>
|
||||||
<item quantity="other">%d nových kontaktů bylo přidáno.</item>
|
<item quantity="other">%d nových kontaktů bylo přidáno.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
@@ -151,6 +157,7 @@
|
|||||||
<plurals name="messages">
|
<plurals name="messages">
|
||||||
<item quantity="one">%d zpráva</item>
|
<item quantity="one">%d zpráva</item>
|
||||||
<item quantity="few">%d zpráv</item>
|
<item quantity="few">%d zpráv</item>
|
||||||
|
<item quantity="many">%d zpráv</item>
|
||||||
<item quantity="other">%d zpráv</item>
|
<item quantity="other">%d zpráv</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_group_is_empty">Tato skupina je prázdná</string>
|
<string name="groups_group_is_empty">Tato skupina je prázdná</string>
|
||||||
@@ -186,6 +193,7 @@
|
|||||||
<plurals name="groups_invitations_open">
|
<plurals name="groups_invitations_open">
|
||||||
<item quantity="one">%d otevřená skupinová pozvánka</item>
|
<item quantity="one">%d otevřená skupinová pozvánka</item>
|
||||||
<item quantity="few">%d otevřených skupinových pozvánek</item>
|
<item quantity="few">%d otevřených skupinových pozvánek</item>
|
||||||
|
<item quantity="many">%d otevřených skupinových pozvánek</item>
|
||||||
<item quantity="other">%d otevřených skupinových pozvánek</item>
|
<item quantity="other">%d otevřených skupinových pozvánek</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_invitations_response_accepted_sent">Přijali jste pozvání do skupiny od %s.</string>
|
<string name="groups_invitations_response_accepted_sent">Přijali jste pozvání do skupiny od %s.</string>
|
||||||
@@ -209,6 +217,7 @@
|
|||||||
<plurals name="posts">
|
<plurals name="posts">
|
||||||
<item quantity="one">%d příspěvek</item>
|
<item quantity="one">%d příspěvek</item>
|
||||||
<item quantity="few">%d příspěvků</item>
|
<item quantity="few">%d příspěvků</item>
|
||||||
|
<item quantity="many">%d příspěvků</item>
|
||||||
<item quantity="other">%d příspěvků</item>
|
<item quantity="other">%d příspěvků</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="forum_new_entry_posted">Záznam byl na fóru zveřejněn</string>
|
<string name="forum_new_entry_posted">Záznam byl na fóru zveřejněn</string>
|
||||||
@@ -240,6 +249,7 @@
|
|||||||
<plurals name="forums_shared">
|
<plurals name="forums_shared">
|
||||||
<item quantity="one">%d fórum sdíleno kontakty</item>
|
<item quantity="one">%d fórum sdíleno kontakty</item>
|
||||||
<item quantity="few">%d fór sdíleno kontakty </item>
|
<item quantity="few">%d fór sdíleno kontakty </item>
|
||||||
|
<item quantity="many">%d fór sdíleno kontakty</item>
|
||||||
<item quantity="other">%d fór sdíleno kontakty</item>
|
<item quantity="other">%d fór sdíleno kontakty</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="nobody">Nikdo</string>
|
<string name="nobody">Nikdo</string>
|
||||||
@@ -362,5 +372,4 @@
|
|||||||
<string name="permission_camera_request_body">Pro scan QR kódu, Briar vyžaduje přístup k fotoaparátu.</string>
|
<string name="permission_camera_request_body">Pro scan QR kódu, Briar vyžaduje přístup k fotoaparátu.</string>
|
||||||
<string name="permission_camera_denied_body">Odmítli jste udělit oprávnění přístupu k fotoaparátu, avšak pro přidání kontaktů je nutné použití fotoaparátu.\n\nZvažte prosím, opětovné udělení přístupu.</string>
|
<string name="permission_camera_denied_body">Odmítli jste udělit oprávnění přístupu k fotoaparátu, avšak pro přidání kontaktů je nutné použití fotoaparátu.\n\nZvažte prosím, opětovné udělení přístupu.</string>
|
||||||
<string name="permission_camera_denied_toast">Oprávnění pro přístup k fotoaparátu nebylo uděleno</string>
|
<string name="permission_camera_denied_toast">Oprávnění pro přístup k fotoaparátu nebylo uděleno</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -375,7 +375,4 @@
|
|||||||
<string name="permission_camera_denied_body">Du hast den Zugriff auf die Kamera verweigert, aber das Hinzufügen von Kontakten erfordert die Verwendung der Kamera.\n\nBitte gewähre den Zugriff.</string>
|
<string name="permission_camera_denied_body">Du hast den Zugriff auf die Kamera verweigert, aber das Hinzufügen von Kontakten erfordert die Verwendung der Kamera.\n\nBitte gewähre den Zugriff.</string>
|
||||||
<string name="permission_camera_denied_toast">Berechtigung für Kamera wurde nicht gewährt</string>
|
<string name="permission_camera_denied_toast">Berechtigung für Kamera wurde nicht gewährt</string>
|
||||||
<string name="qr_code">QR-Code</string>
|
<string name="qr_code">QR-Code</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Von Briar abgemeldet</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Mangels Speicherplatz abgemeldet.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -386,7 +386,4 @@
|
|||||||
<string name="permission_camera_denied_toast">No se concedió el permiso de cámara</string>
|
<string name="permission_camera_denied_toast">No se concedió el permiso de cámara</string>
|
||||||
<string name="qr_code">Código QR</string>
|
<string name="qr_code">Código QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Mostrar código QR a pantalla completa</string>
|
<string name="show_qr_code_fullscreen">Mostrar código QR a pantalla completa</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Desconectado de Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Desconectado por falta de memoria.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
<string name="introduction_onboarding_title">Aurkeztu zure kontaktuak</string>
|
<string name="introduction_onboarding_title">Aurkeztu zure kontaktuak</string>
|
||||||
<string name="introduction_onboarding_text">Zure kontaktuak bata besteari aurkeztu ditzakezu, horrela ez dute aurrez aurre elkartzeko beharra Briar erabiltzeko.</string>
|
<string name="introduction_onboarding_text">Zure kontaktuak bata besteari aurkeztu ditzakezu, horrela ez dute aurrez aurre elkartzeko beharra Briar erabiltzeko.</string>
|
||||||
<string name="introduction_activity_title">Hautatu kontaktua</string>
|
<string name="introduction_activity_title">Hautatu kontaktua</string>
|
||||||
|
<string name="introduction_not_possible">Baduzu aurkezpen bat abian kontaktu hauekin. Baimendu hura bukatzea aurretik. Zure kontaktuak gutxitan konektatzen badira honek denbora bat behar lezake.</string>
|
||||||
<string name="introduction_message_title">Aurkeztu kontaktuak</string>
|
<string name="introduction_message_title">Aurkeztu kontaktuak</string>
|
||||||
<string name="introduction_message_hint">Gehitu mezu bat (aukerazkoa)</string>
|
<string name="introduction_message_hint">Gehitu mezu bat (aukerazkoa)</string>
|
||||||
<string name="introduction_button">Egin aurkezpena</string>
|
<string name="introduction_button">Egin aurkezpena</string>
|
||||||
@@ -145,6 +146,7 @@
|
|||||||
<string name="introduction_request_exists_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu dizu, baina %2$s badago zure kontaktuen zerrendan. Agian %1$s erabiltzaileak ez daki, erantzun dezakezu:</string>
|
<string name="introduction_request_exists_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu dizu, baina %2$s badago zure kontaktuen zerrendan. Agian %1$s erabiltzaileak ez daki, erantzun dezakezu:</string>
|
||||||
<string name="introduction_request_answered_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu du.</string>
|
<string name="introduction_request_answered_received">%1$s erabiltzaileak %2$s zuri aurkeztea eskatu du.</string>
|
||||||
<string name="introduction_response_accepted_sent">%1$s erabiltzailearen aurkezpena onartu duzu.</string>
|
<string name="introduction_response_accepted_sent">%1$s erabiltzailearen aurkezpena onartu duzu.</string>
|
||||||
|
<string name="introduction_response_accepted_sent_info">%1$s zure kontaktuetara gehitu aurretik, aurkezpena onartu behar dute ere. Honek denbora bat behar lezake.</string>
|
||||||
<string name="introduction_response_declined_sent">%1$s erabiltzailearen aurkezpena ukatu duzu.</string>
|
<string name="introduction_response_declined_sent">%1$s erabiltzailearen aurkezpena ukatu duzu.</string>
|
||||||
<string name="introduction_response_accepted_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena onartu du.</string>
|
<string name="introduction_response_accepted_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena onartu du.</string>
|
||||||
<string name="introduction_response_declined_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena ukatu du.</string>
|
<string name="introduction_response_declined_received">%1$s erabiltzaileak %2$s erabiltzailearen aurkezpena ukatu du.</string>
|
||||||
@@ -154,6 +156,7 @@
|
|||||||
<item quantity="other">%d kontaktu berri gehituta.</item>
|
<item quantity="other">%d kontaktu berri gehituta.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
|
<string name="groups_list_empty">Ez dago talderik erakusteko\n\nSakatu + ikonoa talde bat sortzeko, edo eskatu zure kontaktuei taldeak zurekin partekatzea</string>
|
||||||
<string name="groups_created_by">%s erabiltzaileak sortuta</string>
|
<string name="groups_created_by">%s erabiltzaileak sortuta</string>
|
||||||
<plurals name="messages">
|
<plurals name="messages">
|
||||||
<item quantity="one">mezu %d</item>
|
<item quantity="one">mezu %d</item>
|
||||||
@@ -206,6 +209,7 @@
|
|||||||
<string name="groups_reveal_visible_revealed_by_contact">Kontaktuen erlazioa taldean ikusgai dago (%s erabiltzaileak argitara emana)</string>
|
<string name="groups_reveal_visible_revealed_by_contact">Kontaktuen erlazioa taldean ikusgai dago (%s erabiltzaileak argitara emana)</string>
|
||||||
<string name="groups_reveal_invisible">Kontaktuen erlazioa ez dago taldean ikusgai</string>
|
<string name="groups_reveal_invisible">Kontaktuen erlazioa ez dago taldean ikusgai</string>
|
||||||
<!--Forums-->
|
<!--Forums-->
|
||||||
|
<string name="no_forums">Ez dago fororik erakusteko\n\nSakatu + ikonoa talde bat sortzeko, edo eskatu zure kontaktuei foroak zurekin partekatzea</string>
|
||||||
<string name="create_forum_title">Sortu foroa</string>
|
<string name="create_forum_title">Sortu foroa</string>
|
||||||
<string name="choose_forum_hint">Hautatu zure foroaren izena</string>
|
<string name="choose_forum_hint">Hautatu zure foroaren izena</string>
|
||||||
<string name="create_forum_button">Sortu foroa</string>
|
<string name="create_forum_button">Sortu foroa</string>
|
||||||
@@ -222,17 +226,21 @@
|
|||||||
<string name="btn_reply">Erantzun</string>
|
<string name="btn_reply">Erantzun</string>
|
||||||
<string name="forum_leave">Utzi foroa</string>
|
<string name="forum_leave">Utzi foroa</string>
|
||||||
<string name="dialog_title_leave_forum">Berretsi foroa uztea</string>
|
<string name="dialog_title_leave_forum">Berretsi foroa uztea</string>
|
||||||
|
<string name="dialog_message_leave_forum">Ziur foro hau utzi nahi duzula?\n\nForo hau beste norbaitekin partekatu baduzu agian ez dituzte eguneraketak jasoko.</string>
|
||||||
<string name="dialog_button_leave">Utzi</string>
|
<string name="dialog_button_leave">Utzi</string>
|
||||||
|
<string name="forum_left_toast">Foroa utzi du</string>
|
||||||
<!--Forum Sharing-->
|
<!--Forum Sharing-->
|
||||||
<string name="forum_share_button">Partekatu foroa</string>
|
<string name="forum_share_button">Partekatu foroa</string>
|
||||||
<string name="contacts_selected">Kontaktuak hautatuta</string>
|
<string name="contacts_selected">Kontaktuak hautatuta</string>
|
||||||
<string name="activity_share_toolbar_header">Hautatu kontaktuak</string>
|
<string name="activity_share_toolbar_header">Hautatu kontaktuak</string>
|
||||||
|
<string name="no_contacts_selector">Ez dago kontakturik erakusteko\n\nItzuli hona kontakturen bat gehitu eta gero</string>
|
||||||
<string name="forum_shared_snackbar">Foroa partekatuta hautatutako kontaktuekin</string>
|
<string name="forum_shared_snackbar">Foroa partekatuta hautatutako kontaktuekin</string>
|
||||||
<string name="forum_share_message">Gehitu mezua (aukerazkoa)</string>
|
<string name="forum_share_message">Gehitu mezua (aukerazkoa)</string>
|
||||||
<string name="forum_share_error">Errore bat egon da foro hau partekatzean.</string>
|
<string name="forum_share_error">Errore bat egon da foro hau partekatzean.</string>
|
||||||
<string name="forum_invitation_received">%1$s erabiltzaileak \"%2$s\" foroa partekatu du zurekin.</string>
|
<string name="forum_invitation_received">%1$s erabiltzaileak \"%2$s\" foroa partekatu du zurekin.</string>
|
||||||
<string name="forum_invitation_sent">\"%1$s\" foroa partekatu duzu %2$s erabiltzailearekin.</string>
|
<string name="forum_invitation_sent">\"%1$s\" foroa partekatu duzu %2$s erabiltzailearekin.</string>
|
||||||
<string name="forum_invitations_title">Forora gonbidapenak</string>
|
<string name="forum_invitations_title">Forora gonbidapenak</string>
|
||||||
|
<string name="forum_invitation_exists">Foro honetarako gonbidapen bat onartu duzu jada. Gonbidapen gehiago onartzeak foroarekin konexioa azkarrago eta egonkorragoa egingo du.</string>
|
||||||
<string name="forum_joined_toast">Forora elkartuta</string>
|
<string name="forum_joined_toast">Forora elkartuta</string>
|
||||||
<string name="forum_declined_toast">Gonbidapena ukatuta</string>
|
<string name="forum_declined_toast">Gonbidapena ukatuta</string>
|
||||||
<string name="shared_by_format">%s erabiltzaileak partekatuta</string>
|
<string name="shared_by_format">%s erabiltzaileak partekatuta</string>
|
||||||
@@ -258,7 +266,9 @@
|
|||||||
<string name="blogs_blog_post_created">Blog sarrera sortuta</string>
|
<string name="blogs_blog_post_created">Blog sarrera sortuta</string>
|
||||||
<string name="blogs_blog_post_received">Blog sarrera berria jasota</string>
|
<string name="blogs_blog_post_received">Blog sarrera berria jasota</string>
|
||||||
<string name="blogs_blog_post_scroll_to">Korritu hona</string>
|
<string name="blogs_blog_post_scroll_to">Korritu hona</string>
|
||||||
|
<string name="blogs_feed_empty_state">Ez dago sarrerarik erakusteko\n\nZure kontaktuen eta harpidetutako sarrerak bidalketak hemen agertuko dira\n\nSakatu arkatzaren ikonoa sarrera bat idazteko</string>
|
||||||
<string name="blogs_remove_blog">Kendu bloga</string>
|
<string name="blogs_remove_blog">Kendu bloga</string>
|
||||||
|
<string name="blogs_remove_blog_dialog_message">Ziur blog hau kendu nahi duzula?\n\nSarrerak zure gailutik kenduko dira baina ez besteen gailuetatik.\n\nBlog hau beste inorekin partekatu baduzu agian eguneraketak jasotzeari utziko diote.</string>
|
||||||
<string name="blogs_remove_blog_ok">Kendu</string>
|
<string name="blogs_remove_blog_ok">Kendu</string>
|
||||||
<string name="blogs_blog_removed">Blog-a kenduta</string>
|
<string name="blogs_blog_removed">Blog-a kenduta</string>
|
||||||
<string name="blogs_reblog_comment_hint">Gehitu iruzkina (aukerazkoa)</string>
|
<string name="blogs_reblog_comment_hint">Gehitu iruzkina (aukerazkoa)</string>
|
||||||
@@ -288,6 +298,7 @@
|
|||||||
<string name="blogs_rss_feeds_manage_author">Egilea:</string>
|
<string name="blogs_rss_feeds_manage_author">Egilea:</string>
|
||||||
<string name="blogs_rss_feeds_manage_updated">Azken eguneraketa:</string>
|
<string name="blogs_rss_feeds_manage_updated">Azken eguneraketa:</string>
|
||||||
<string name="blogs_rss_remove_feed">Kendu jarioa:</string>
|
<string name="blogs_rss_remove_feed">Kendu jarioa:</string>
|
||||||
|
<string name="blogs_rss_remove_feed_dialog_message">Ziur jario hau kendu nahi duzula?\n\nSarrerak zure gailutik kenduko dira baina ez besteen gailuetatik.\n\nJario hau beste inorekin partekatu baduzu agian eguneraketak jasotzeari utziko diote.</string>
|
||||||
<string name="blogs_rss_remove_feed_ok">Kendu</string>
|
<string name="blogs_rss_remove_feed_ok">Kendu</string>
|
||||||
<string name="blogs_rss_feeds_manage_delete_error">Ezin izan da jarioa ezabatu!</string>
|
<string name="blogs_rss_feeds_manage_delete_error">Ezin izan da jarioa ezabatu!</string>
|
||||||
<string name="blogs_rss_feeds_manage_empty_state">RSS jariorik ez erakusteko\n\nSakatu + ikonoa jario bat inportatzeko</string>
|
<string name="blogs_rss_feeds_manage_empty_state">RSS jariorik ez erakusteko\n\nSakatu + ikonoa jario bat inportatzeko</string>
|
||||||
@@ -382,7 +393,4 @@
|
|||||||
<string name="permission_camera_denied_toast">Eza kameraren baimenik eman</string>
|
<string name="permission_camera_denied_toast">Eza kameraren baimenik eman</string>
|
||||||
<string name="qr_code">QR kodea</string>
|
<string name="qr_code">QR kodea</string>
|
||||||
<string name="show_qr_code_fullscreen">Erakutsi QR kodea pantaila osoan</string>
|
<string name="show_qr_code_fullscreen">Erakutsi QR kodea pantaila osoan</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Briar saioa amaituta</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Saioa amaituta memoria faltagatik</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
312
briar-android/src/main/res/values-fa/strings.xml
Normal file
312
briar-android/src/main/res/values-fa/strings.xml
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<resources>
|
||||||
|
<!--Setup-->
|
||||||
|
<string name="setup_title">به برایر خوش آمدید</string>
|
||||||
|
<string name="setup_name_explanation">نام مستعارتان کنار هر مطلب شما قرار خواهد گرفت و بعد از ایجاد حساب کاربری امکان تغییر آن وجود ندارد.</string>
|
||||||
|
<string name="setup_next">بعدی</string>
|
||||||
|
<string name="setup_password_intro">یک رمز عبور انتخاب کنید</string>
|
||||||
|
<string name="setup_doze_title">اتصال های پس زمینه</string>
|
||||||
|
<string name="setup_doze_intro">برای دریافت پیام ها، برایر نیاز دارد تا در پس زمینه اتصال داشته باشد.</string>
|
||||||
|
<string name="setup_doze_button">اجازه دادن به اتصالات</string>
|
||||||
|
<string name="choose_nickname">نام مستعار خود را انتخاب کنید</string>
|
||||||
|
<string name="choose_password">رمز عبور خود را انتخاب کنید</string>
|
||||||
|
<string name="confirm_password">رمز عبور خود را تایید کنید</string>
|
||||||
|
<string name="name_too_long">نام بیش از حد طولانی می باشد</string>
|
||||||
|
<string name="password_too_weak">رمز عبور ضعیف می باشد</string>
|
||||||
|
<string name="passwords_do_not_match">رمز های عبور مطابقت ندارند </string>
|
||||||
|
<string name="create_account_button">ایجاد حساب کاربری</string>
|
||||||
|
<string name="more_info">اطلاعات بیشتر</string>
|
||||||
|
<string name="don_t_ask_again">دیگر نپرس</string>
|
||||||
|
<string name="setup_huawei_text">لطفا روی دکمه زیر کلیک کنید و مطمئن شوید که از برایر در صفحه \"برنامه های محافظت شده\" محافظت می شود.</string>
|
||||||
|
<string name="setup_huawei_button">حفاظت از برایر</string>
|
||||||
|
<string name="setup_huawei_help">اگر برایر به فهرست برنامه های محافظت شده اضافه نشده، نمی تواند در پس زمینه مشغول به کار باشد.</string>
|
||||||
|
<!--Login-->
|
||||||
|
<string name="enter_password">رمز عبور خود را وارد کنید:</string>
|
||||||
|
<string name="try_again">رمز عبور اشتباه است، لطفا دوباره سعی کنید</string>
|
||||||
|
<string name="sign_in_button">ورود</string>
|
||||||
|
<string name="forgotten_password">رمز عبور را فراموش کرده ام</string>
|
||||||
|
<string name="startup_failed_notification_text">برای اطلاعات بیشتر کلیک کنید</string>
|
||||||
|
<string name="startup_failed_data_too_old_error">حساب کاربری شما با یک نسخه قدیمی از این برنامه ایجاد شده است و به همین خاطربا این نسخه نمی تواند باز شود. شما باید نسخه قدیمی را دوباره نصب کنید یا یک حساب کاربری جدید با \"رمز عبور ام را فراموش کرده ام\" در پرامپت رمز عبور ایجاد کنید.</string>
|
||||||
|
<string name="startup_failed_data_too_new_error">این نسخه از برنامه قدیمی می باشد. لطفا به آخرین نسخه از برنامه ارتقاء داده و دوباره سعی کنید.</string>
|
||||||
|
<plurals name="expiry_warning">
|
||||||
|
<item quantity="one">این یک نسخه آزمایشی از برایر می باشد. حساب کاربری شما در %d روز آینده به پایان می رسد و امکان تمدید آن وجود نخواهد داشت.</item>
|
||||||
|
<item quantity="other">این یک نسخه آزمایشی از برایر می باشد. حساب کاربری شما در %d روز آینده به پایان می رسد و امکان تمدید آن وجود نخواهد داشت.</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="expiry_update">تاریخ اتمام آزمایش افزایش یافته است. حساب کاربری شما در %d روز آینده به پایان می رسد.</string>
|
||||||
|
<string name="download_briar">برای اینکه به استفاده خود از برایر ادامه دهید، لطفا نسخه ۱.۰ را دانلود کنید.</string>
|
||||||
|
<string name="create_new_account">لازم است تا یک حساب کاربری جدید ایجاد کنید، می توانید از نام مستعار یکسان برای حساب های کاربری استفاده کنید.</string>
|
||||||
|
<string name="download_briar_button">دانلود برایر 1.0</string>
|
||||||
|
<string name="startup_open_database">رمزگشایی سیستم ...</string>
|
||||||
|
<string name="startup_migrate_database">به روز رسانی سیستم ...</string>
|
||||||
|
<!--Navigation Drawer-->
|
||||||
|
<string name="nav_drawer_open_description">باز کردن منوی برنامه</string>
|
||||||
|
<string name="nav_drawer_close_description">بستن منوی برنامه</string>
|
||||||
|
<string name="contact_list_button">مخاطبین</string>
|
||||||
|
<string name="groups_button">گروه های خصوصی</string>
|
||||||
|
<string name="forums_button">تالار های گفتمان</string>
|
||||||
|
<string name="blogs_button">بلاگ ها</string>
|
||||||
|
<string name="settings_button">تنظیمات</string>
|
||||||
|
<string name="sign_out_button">خروج</string>
|
||||||
|
<!--Transports-->
|
||||||
|
<string name="transport_tor">اینترنت</string>
|
||||||
|
<string name="transport_bt">بلوتوث</string>
|
||||||
|
<string name="transport_lan">وای فای</string>
|
||||||
|
<!--Notifications-->
|
||||||
|
<string name="ongoing_notification_text">برای باز کردن برایر کلیک کنید.</string>
|
||||||
|
<plurals name="private_message_notification_text">
|
||||||
|
<item quantity="one">%dپیام خصوصی جدید</item>
|
||||||
|
<item quantity="other">%dپیام خصوصی جدید</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="group_message_notification_text">
|
||||||
|
<item quantity="one">پیام گروه جدید</item>
|
||||||
|
<item quantity="other">%d پیام گروه جدید</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="forum_post_notification_text">
|
||||||
|
<item quantity="one">پست فروم جدید</item>
|
||||||
|
<item quantity="other">%d پست فروم جدید</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="blog_post_notification_text">
|
||||||
|
<item quantity="one">پست پلاگ جدید</item>
|
||||||
|
<item quantity="other">%d پست بلاگ جدید</item>
|
||||||
|
</plurals>
|
||||||
|
<!--Misc-->
|
||||||
|
<string name="now">هم اکنون</string>
|
||||||
|
<string name="show">نمایش</string>
|
||||||
|
<string name="hide">پنهان کردن</string>
|
||||||
|
<string name="ok">تأیید</string>
|
||||||
|
<string name="cancel">لغو</string>
|
||||||
|
<string name="got_it">متوجه شدم</string>
|
||||||
|
<string name="delete">حذف</string>
|
||||||
|
<string name="accept">پذیرفتن</string>
|
||||||
|
<string name="decline">رد کردن</string>
|
||||||
|
<string name="options">گزینه ها</string>
|
||||||
|
<string name="online">آنلاین</string>
|
||||||
|
<string name="offline">آفلاین</string>
|
||||||
|
<string name="send">ارسال</string>
|
||||||
|
<string name="allow">اجازه دادن</string>
|
||||||
|
<string name="open">باز کردن</string>
|
||||||
|
<string name="no_data">داده ای موجود نمی باشد</string>
|
||||||
|
<string name="ellipsis">…</string>
|
||||||
|
<string name="text_too_long">متن وارد شده بیش از حد طولانی می باشد</string>
|
||||||
|
<string name="fix">اصلاح</string>
|
||||||
|
<string name="help">راهنما</string>
|
||||||
|
<string name="sorry">ببخشید</string>
|
||||||
|
<!--Contacts and Private Conversations-->
|
||||||
|
<string name="date_no_private_messages">هیچ پیامی موجود نیست</string>
|
||||||
|
<string name="no_private_messages">هیچ پیامی برای نشان دادن وجود ندارد</string>
|
||||||
|
<string name="message_hint">نوشتن پیام</string>
|
||||||
|
<string name="delete_contact">حذف مخاطب</string>
|
||||||
|
<string name="dialog_title_delete_contact">تایید حذف مخاطب</string>
|
||||||
|
<string name="dialog_message_delete_contact">آیا مطمئن هستید که میخواهید این مخاطب و تمام پیام های تبادل شده با آن را حذف کنید؟</string>
|
||||||
|
<string name="contact_deleted_toast">مخاطب حذف شد</string>
|
||||||
|
<!--Adding Contacts-->
|
||||||
|
<string name="add_contact_title">افزودن مخاطب</string>
|
||||||
|
<string name="face_to_face">برای اضافه کردن فرد به عنوان مخاطب باید با او به صورت حضوری ملاقات کنید.
|
||||||
|
این از جعل هویت شما و یا از خوانده شدن پیام هایتان در آینده جلوگیری خواهد کرد.</string>
|
||||||
|
<string name="continue_button">ادامه</string>
|
||||||
|
<string name="connection_failed">اتصال ناموفق بود</string>
|
||||||
|
<string name="try_again_button">دوباره سعی کنید</string>
|
||||||
|
<string name="contact_exchange_failed">تبادل مخاطب با خطا مواجه شد</string>
|
||||||
|
<string name="qr_code_invalid">کد QR نامعتبر می باشد</string>
|
||||||
|
<!--Introductions-->
|
||||||
|
<string name="introduction_onboarding_text">شما می توانید مخاطبان خود را به یکدیگر معرفی کنید، در این صورت دیگر نیازی به دیدار حضوری برای اتصال روی برایر نمی باشد.</string>
|
||||||
|
<string name="introduction_activity_title">انتخاب مخاطب</string>
|
||||||
|
<string name="introduction_not_possible">شما همین الان یک معرفی در مرحله انجام با این مخاطبان دارید. لطفا اجازه دهید تا این معرفی به پایان برسد. اگر شما و یا مخاطبانتان به ندرت آنلاین هستید، ممکن است کمی زمان ببرد.</string>
|
||||||
|
<string name="introduction_message_title">معرفی مخاطبین</string>
|
||||||
|
<string name="introduction_message_hint">افزودن یک پیام (اختیاری)</string>
|
||||||
|
<string name="introduction_button">معرفی کردن</string>
|
||||||
|
<string name="introduction_sent">معرفی شما فرستاده شد.</string>
|
||||||
|
<string name="introduction_error">خطایی در معرفی کردن رخ داده است.</string>
|
||||||
|
<string name="introduction_response_error">خطا در هنگام پاسخ به معرفی</string>
|
||||||
|
<string name="introduction_request_answered_received">%1$s میخواهد شما را به %2$s معرفی کند.</string>
|
||||||
|
<string name="introduction_response_accepted_sent">شما معرفی به %1$sرا پذیرفتید.</string>
|
||||||
|
<string name="introduction_response_accepted_sent_info">قبل از اضافه شدن %1$s به مخاطبان شما، آن ها باید معرفی را بپذیرند. این شاید کمی زمان ببرد.</string>
|
||||||
|
<string name="introduction_response_declined_sent">شما معرفی به %1$sرا رد کردید.</string>
|
||||||
|
<string name="introduction_response_accepted_received">%1$s معرفی به %2$s را پذیرفت.</string>
|
||||||
|
<string name="introduction_response_declined_received">%1$s معرفی به %2$s را رد کرد.</string>
|
||||||
|
<string name="introduction_response_declined_received_by_introducee">%1$s می گوید که %2$s دعوت نامه را رد کرد.</string>
|
||||||
|
<plurals name="introduction_notification_text">
|
||||||
|
<item quantity="one">مخاطب جدید افزوده شد.</item>
|
||||||
|
<item quantity="other">%d مخاطب جدید افزوده شد.</item>
|
||||||
|
</plurals>
|
||||||
|
<!--Private Groups-->
|
||||||
|
<string name="groups_created_by">ایجاد شده توسط %s</string>
|
||||||
|
<plurals name="messages">
|
||||||
|
<item quantity="one">%d پیام</item>
|
||||||
|
<item quantity="other">%d پیام</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="groups_group_is_empty">این گروه خالی می باشد</string>
|
||||||
|
<string name="groups_group_is_dissolved">این گروه منحل شده است</string>
|
||||||
|
<string name="groups_remove">حذف</string>
|
||||||
|
<string name="groups_create_group_title">ایجاد گروه خصوصی</string>
|
||||||
|
<string name="groups_create_group_button">ایجاد گروه</string>
|
||||||
|
<string name="groups_create_group_invitation_button">ارسال دعوت نامه</string>
|
||||||
|
<string name="groups_create_group_hint">یک نام برای گروه شخصی خود انتخاب کنید</string>
|
||||||
|
<string name="groups_invitation_sent">دعوت نامه گروه فرستاده شد</string>
|
||||||
|
<string name="groups_message_sent">پیام فرستاده شد</string>
|
||||||
|
<string name="groups_member_list">لیست اعضا</string>
|
||||||
|
<string name="groups_invite_members">دعوت اعضا</string>
|
||||||
|
<string name="groups_member_created_you">شما گروه را ایجاد کردید</string>
|
||||||
|
<string name="groups_member_created">%s گروه را ایجاد کرد</string>
|
||||||
|
<string name="groups_member_joined_you">شما به عضویت گروه درآمدید</string>
|
||||||
|
<string name="groups_member_joined">%sعضو گروه شد</string>
|
||||||
|
<string name="groups_leave">ترک گروه</string>
|
||||||
|
<string name="groups_leave_dialog_title">تایید ترک گروه</string>
|
||||||
|
<string name="groups_leave_dialog_message">مطمئن هستید که میخواهید این گروه را ترک کنید؟</string>
|
||||||
|
<string name="groups_dissolve">انحلال گروه</string>
|
||||||
|
<string name="groups_dissolve_dialog_title">تایید انحلال گروه</string>
|
||||||
|
<string name="groups_dissolve_button">انحلال</string>
|
||||||
|
<string name="groups_dissolved_dialog_title">گروه انحلال یافت</string>
|
||||||
|
<!--Private Group Invitations-->
|
||||||
|
<string name="groups_invitations_title">دعوت نامه های گروه</string>
|
||||||
|
<string name="groups_invitations_invitation_sent">شما %1$s را برای عضویت به گروه \"%2$s\" دعوت کردید.</string>
|
||||||
|
<string name="groups_invitations_invitation_received">%1$s شما را دعوت کرده تا عضو گروه \"%2$s\" شوید.</string>
|
||||||
|
<string name="groups_invitations_declined">دعوت نامه گروه رد شد</string>
|
||||||
|
<string name="groups_invitations_response_accepted_sent">شما دعوت نامه گروه از %s را پذیرفتید.</string>
|
||||||
|
<string name="groups_invitations_response_declined_sent">شما دعوت نامه گروه از %s را رد کردید.</string>
|
||||||
|
<string name="groups_invitations_response_accepted_received">%sدعوت نامه گروه را پذیرفت.</string>
|
||||||
|
<string name="groups_invitations_response_declined_received">%s دعوت نامه گروه را رد کرد.</string>
|
||||||
|
<string name="sharing_status_groups">فقط سازنده گروه می تواند اعضای جدید را به گروه دعوت کند. در پایین تمام اعضای فعلی گروه آمده است.</string>
|
||||||
|
<!--Private Groups Revealing Contacts-->
|
||||||
|
<string name="groups_reveal_contacts">نشان دادن مخاطبان</string>
|
||||||
|
<!--Forums-->
|
||||||
|
<string name="create_forum_title">ایجاد فروم</string>
|
||||||
|
<string name="choose_forum_hint">انتخاب یک نام برای فروم</string>
|
||||||
|
<string name="create_forum_button">ایجاد فروم</string>
|
||||||
|
<string name="forum_created_toast">فروم ایجاد شد</string>
|
||||||
|
<string name="no_forum_posts">هیچ پستی برای نشان دادن وجود ندارد</string>
|
||||||
|
<string name="no_posts">هیچ پستی وجود ندارد</string>
|
||||||
|
<plurals name="posts">
|
||||||
|
<item quantity="one">%d پست</item>
|
||||||
|
<item quantity="other">%d پست</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="forum_message_reply_hint">پاسخ جدید</string>
|
||||||
|
<string name="btn_reply">پاسخ</string>
|
||||||
|
<string name="forum_leave">ترک فروم</string>
|
||||||
|
<string name="dialog_title_leave_forum">تأیید ترک فروم</string>
|
||||||
|
<string name="dialog_button_leave">ترک</string>
|
||||||
|
<string name="forum_left_toast">ترک فروم</string>
|
||||||
|
<!--Forum Sharing-->
|
||||||
|
<string name="forum_share_button">اشتراک گذاری فروم</string>
|
||||||
|
<string name="contacts_selected">مخاطبان انتخاب شدند</string>
|
||||||
|
<string name="activity_share_toolbar_header">انتخاب مخاطبان</string>
|
||||||
|
<string name="forum_shared_snackbar">فروم با مخاطبان انتخاب شده به اشتراک گذاشته شد</string>
|
||||||
|
<string name="forum_share_message">افزودن یک پیام (اختیاری)</string>
|
||||||
|
<string name="forum_share_error">خطایی با اشتراک گذاری این فروم رخ داد</string>
|
||||||
|
<string name="forum_invitation_received">%1$s فروم \"%2$s\" را با شما به اشتراک گذاشته است.</string>
|
||||||
|
<string name="forum_invitation_sent">شما فروم \"%1$s\" را با %2$s به اشتراک گذاشتید.</string>
|
||||||
|
<string name="forum_invitations_title">دعوت نامه های فروم</string>
|
||||||
|
<string name="forum_declined_toast">دعوت نامه رد شد</string>
|
||||||
|
<string name="shared_by_format">به اشتراک گذاشته شده توسط %s</string>
|
||||||
|
<string name="forum_invitation_response_accepted_received">%s دعوت نامه فروم را پذیرفت.</string>
|
||||||
|
<string name="forum_invitation_response_declined_received">%s دعوت نامه فروم را رد کرد.</string>
|
||||||
|
<string name="sharing_status">به اشتراک گذاری وضعیت</string>
|
||||||
|
<string name="sharing_status_forum">هر عضو فروم می تواند آن را با دیگر مخاطبان خود به اشتراک بگذارد. شما این فروم را با مخاطبان زیر به اشتراک می گذارید. ممکن است اعضای دیگری هم باشند که شما نمی توانید آن ها را ببینید.</string>
|
||||||
|
<string name="nobody">هیچکس</string>
|
||||||
|
<!--Blogs-->
|
||||||
|
<string name="blogs_other_blog_empty_state">هیچ پستی برای نشان دادن وجود ندارد</string>
|
||||||
|
<string name="read_more">بیشتر بخوانید</string>
|
||||||
|
<string name="blogs_write_blog_post">نوشتن پست بلاگ</string>
|
||||||
|
<string name="blogs_write_blog_post_body_hint">پست بلاگ خود را بنویسید</string>
|
||||||
|
<string name="blogs_publish_blog_post">انتشار</string>
|
||||||
|
<string name="blogs_blog_post_created">پست بلاگ ایجاد شد</string>
|
||||||
|
<string name="blogs_blog_post_received">پست جدید بلاگ دریافت شد</string>
|
||||||
|
<string name="blogs_remove_blog">حذف بلاگ</string>
|
||||||
|
<string name="blogs_remove_blog_ok">حذف</string>
|
||||||
|
<string name="blogs_blog_removed">بلاگ حذف شد</string>
|
||||||
|
<string name="blogs_reblog_comment_hint">افزودن یک کامنت (اختیاری)</string>
|
||||||
|
<!--Blog Sharing-->
|
||||||
|
<string name="blogs_sharing_share">به اشتراک گذاری بلاگ</string>
|
||||||
|
<string name="blogs_sharing_button">به اشتراک گذاری بلاگ</string>
|
||||||
|
<string name="blogs_sharing_snackbar">بلاگ با مخاطبان انتخاب شده به اشتراک گذاشته شد</string>
|
||||||
|
<string name="blogs_sharing_response_accepted_sent">شما دعوت نامه بلاگ از طرف %s را پذیرفتید.</string>
|
||||||
|
<string name="blogs_sharing_response_declined_sent">شما دعوت نامه بلاگ از %s را رد کردید.</string>
|
||||||
|
<string name="blogs_sharing_response_accepted_received">%sدعوت نامه بلاگ را پذیرفت.</string>
|
||||||
|
<string name="blogs_sharing_response_declined_received">%s دعوت نامه بلاگ را رد کرد.</string>
|
||||||
|
<string name="blogs_sharing_invitation_received">%1$s بلاگ \"%2$s\" را با شما به اشتراک گذاشت.</string>
|
||||||
|
<string name="blogs_sharing_invitation_sent">شما بلاگ \"%1$s\" را با %2$s به اشتراک گذاشته اید.</string>
|
||||||
|
<string name="blogs_sharing_invitations_title">دعوت نامه های بلاگ</string>
|
||||||
|
<string name="blogs_sharing_declined_toast">دعوت نامه رد شد</string>
|
||||||
|
<!--RSS Feeds-->
|
||||||
|
<string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string>
|
||||||
|
<string name="blogs_rss_feeds_import_error">متاسفیم! وارد کردن خوراک شما با خطا مواجه شده است.</string>
|
||||||
|
<string name="blogs_rss_feeds_manage">مدیریت خوراک های RSS</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_imported">وارد شده:</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_author">نویسنده:</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_updated">آخرین به روز رسانی:</string>
|
||||||
|
<string name="blogs_rss_remove_feed">حذف فید</string>
|
||||||
|
<string name="blogs_rss_remove_feed_ok">حذف</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_delete_error">خوراک نمی تواند پاک شود!</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_error">مشکلی با بارگذاری فیدهای شما وجود داشت. لطفا بعدا امتحان کنید.</string>
|
||||||
|
<!--Settings Network-->
|
||||||
|
<string name="network_settings_title">شبکه ها</string>
|
||||||
|
<string name="bluetooth_setting">اتصال از طریق بلوتوث</string>
|
||||||
|
<string name="bluetooth_setting_enabled">هر زمانی که مخاطبان نزدیک هستند</string>
|
||||||
|
<string name="bluetooth_setting_disabled">فقط در هنگام افزودن مخاطبان</string>
|
||||||
|
<string name="tor_network_setting">اتصال از طریق تور</string>
|
||||||
|
<string name="tor_network_setting_never">هرگز</string>
|
||||||
|
<string name="tor_network_setting_wifi">فقط در هنگام استفاده از وای فای</string>
|
||||||
|
<string name="tor_network_setting_always">هنگام استفاده از وای فای یا موبایل دیتا</string>
|
||||||
|
<!--Settings Security and Panic-->
|
||||||
|
<string name="security_settings_title">امنیت</string>
|
||||||
|
<string name="change_password">تغییر رمز عبور</string>
|
||||||
|
<string name="current_password">رمز عبور فعلی خود را وارد کنید:</string>
|
||||||
|
<string name="choose_new_password">رمز عبور جدید خود را انتخاب کنید:</string>
|
||||||
|
<string name="confirm_new_password">رمز عبور جدید خود را تأیید کنید:</string>
|
||||||
|
<string name="password_changed">رمز عبور تغییر کرده است</string>
|
||||||
|
<string name="panic_setting_title">دکمه هراس</string>
|
||||||
|
<string name="panic_app_setting_title">برنامه دکمه هراس</string>
|
||||||
|
<string name="unknown_app">یک برنامه ناشناخته</string>
|
||||||
|
<string name="panic_app_setting_summary">هیچ برنامه تنظیم نشده است</string>
|
||||||
|
<string name="panic_app_setting_none">هیچکدام</string>
|
||||||
|
<string name="lock_setting_title">خروج</string>
|
||||||
|
<string name="lock_setting_summary">در صورت کلیک بر روی کلید هراس از برایر خارج شو</string>
|
||||||
|
<string name="purge_setting_title">حذف حساب کاربری</string>
|
||||||
|
<string name="uninstall_setting_title">پاک کردن برایر</string>
|
||||||
|
<!--Settings Notifications-->
|
||||||
|
<string name="notify_private_messages_setting_title">پیام های خصوصی</string>
|
||||||
|
<string name="notify_private_messages_setting_summary">نمایش هشدار برای پیام های خصوصی</string>
|
||||||
|
<string name="notify_group_messages_setting_title">پیام های گروه</string>
|
||||||
|
<string name="notify_group_messages_setting_summary">نمایش هشدار برای پیام های گروه</string>
|
||||||
|
<string name="notify_forum_posts_setting_title">پست های فروم</string>
|
||||||
|
<string name="notify_forum_posts_setting_summary">نمایش هشدار برای پست های فروم</string>
|
||||||
|
<string name="notify_blog_posts_setting_title">پست های بلاگ</string>
|
||||||
|
<string name="notify_blog_posts_setting_summary">نمایش هشدار برای پست های بلاگ</string>
|
||||||
|
<string name="notify_lock_screen_setting_title">قفل صفحه</string>
|
||||||
|
<string name="notify_lock_screen_setting_summary">نمایش نوتیفیکشن روی صفحه قفل</string>
|
||||||
|
<string name="notify_sound_setting">صدا</string>
|
||||||
|
<string name="notify_sound_setting_default">رینگتون پیش فرض</string>
|
||||||
|
<string name="notify_sound_setting_disabled">هیچکدام</string>
|
||||||
|
<string name="choose_ringtone_title">انتخاب رینگتون</string>
|
||||||
|
<string name="cannot_load_ringtone">ناتوانی در بارگذاری رینگتون</string>
|
||||||
|
<!--Settings Feedback-->
|
||||||
|
<string name="feedback_settings_title">بازخورد</string>
|
||||||
|
<string name="send_feedback">ارسال بازخورد</string>
|
||||||
|
<!--Link Warning-->
|
||||||
|
<string name="link_warning_title">هشدار لینک</string>
|
||||||
|
<string name="link_warning_intro">با باز کردن لینک زیر شما یک برنامه بیرونی را باز خواهید کرد.</string>
|
||||||
|
<string name="link_warning_text">این می تواند برای شناسایی شما مورد استفاده قرار بگیرد. قبل از باز کردن آن به قابل اطمینان بودن شخصی که آن را برای شما ارسال کرده فکر کنید و بعد برای احتیاط آن را با ارفاکس باز کنید.</string>
|
||||||
|
<string name="link_warning_open_link">باز کردن لینک</string>
|
||||||
|
<!--Crash Reporter-->
|
||||||
|
<string name="crash_report_title">گزارش خطای برایر</string>
|
||||||
|
<string name="briar_crashed">ببخشید، برایر از کار افتاده است.</string>
|
||||||
|
<string name="not_your_fault">این تقصیر شما نیست.</string>
|
||||||
|
<string name="please_send_report">لطفا با فرستادن گزارش خطا به ما کمک کنید تا برایر را بهتر کنیم.</string>
|
||||||
|
<string name="report_is_encrypted">به شما اطمینان می دهیم که گزارش شما رمزنگاری شده و به صورت امن فرستاده می شود.</string>
|
||||||
|
<string name="feedback_title">بازخورد</string>
|
||||||
|
<string name="describe_crash">توضیح دهید چه اتفاقی افتاد (اختیاری)</string>
|
||||||
|
<string name="enter_feedback">بازخورد خود را وارد کنید</string>
|
||||||
|
<string name="optional_contact_email">آدرس ایمیل شما (اختیاری)</string>
|
||||||
|
<string name="could_not_load_report_data">امکان بارگذاری داده های گزارش وجود ندارد.</string>
|
||||||
|
<string name="send_report">ارسال گزارش</string>
|
||||||
|
<string name="close">بستن</string>
|
||||||
|
<string name="dev_report_saved">گزارش ذخیره شد. دفعه بعدی که وارد برایر شدید فرستاده خواهد شد.</string>
|
||||||
|
<!--Sign Out-->
|
||||||
|
<string name="progress_title_logout">خروج از برایر...</string>
|
||||||
|
<!--Screen Filters & Tapjacking-->
|
||||||
|
<!--Permission Requests-->
|
||||||
|
<string name="permission_camera_title">دسترسی به دوربین</string>
|
||||||
|
<string name="permission_camera_request_body">برای اسکن کردن کد QR دسترسی به دوربین لازم است.</string>
|
||||||
|
<string name="permission_camera_denied_toast">اجازه دسترسی به دوربین پذیرفته نشد</string>
|
||||||
|
<string name="qr_code">کد QR</string>
|
||||||
|
</resources>
|
||||||
@@ -27,12 +27,15 @@
|
|||||||
<string name="enter_password">Syötä salasana:</string>
|
<string name="enter_password">Syötä salasana:</string>
|
||||||
<string name="try_again">Väärä salasana, yritä uudelleen</string>
|
<string name="try_again">Väärä salasana, yritä uudelleen</string>
|
||||||
<string name="sign_in_button">Kirjaudu sisään</string>
|
<string name="sign_in_button">Kirjaudu sisään</string>
|
||||||
<string name="forgotten_password">Olen unohtanut salasanan</string>
|
<string name="forgotten_password">Olen unohtanut salasanani</string>
|
||||||
<string name="dialog_title_lost_password">Unohtunut salasana</string>
|
<string name="dialog_title_lost_password">Unohtunut salasana</string>
|
||||||
<string name="dialog_message_lost_password">Sinun Briar tili on tallennettu salattuna sinun laitteelle, ei pilvipalvelimelle, joten emme voi palauttaa salasanaasi. Haluatko poistaa tilisi ja aloittaa alusta?\n\nVaroitus: Tulet menettämään tunnuksesi, yhteystietosi ja viestisi lopullisesti.</string>
|
<string name="dialog_message_lost_password">Sinun Briar tili on tallennettu salattuna sinun laitteelle, ei pilvipalvelimelle, joten emme voi palauttaa salasanaasi. Haluatko poistaa tilisi ja aloittaa alusta?\n\nVaroitus: Tulet menettämään tunnuksesi, yhteystietosi ja viestisi lopullisesti.</string>
|
||||||
<string name="startup_failed_notification_title">Briarin käynnistys epäonnistui</string>
|
<string name="startup_failed_notification_title">Briarin käynnistys epäonnistui</string>
|
||||||
<string name="startup_failed_notification_text">Napauta nähdäksesi lisätietoja.</string>
|
<string name="startup_failed_notification_text">Napauta nähdäksesi lisätietoja.</string>
|
||||||
<string name="startup_failed_activity_title">Briarin käynnistys epäonnistui</string>
|
<string name="startup_failed_activity_title">Briarin käynnistys epäonnistui</string>
|
||||||
|
<string name="startup_failed_db_error">Jostain syystä sinun Briar tietokanta on korruptoitunut korjauskelvottomaksi. Tilisi, tietosi ja kaikki yhteystietosi on menetetty. Valitettavasti, sinun täytyy asentaa Briar uudelleen ja luoda uusi tili valitsemalla \'Olen unohtanut salasanani\' kun sinulta kysytään salasanaa.</string>
|
||||||
|
<string name="startup_failed_data_too_old_error">Sinun tili luotiin vanhalla versiolla eikä sitä voida avata tällä versiolla. Sinun täytyy joko asentaa vanha versio uudelleen tai luoda uusi tili valitsemalla \'Olen unohtanut salasanani\' kun sinulta kysytään salasanaa.</string>
|
||||||
|
<string name="startup_failed_data_too_new_error">Tämän sovelluksen versio on liian vanha. Päivitä viimeisimpään versioon ja yritä uudelleen.</string>
|
||||||
<string name="startup_failed_service_error">Briar ei kyennyt käynnistämään vaadittua liitännäistä. Briarin uudelleenasennus yleensä korjaa ongelman. Huomaa kuitenkin, että tulet menettämään tilisi ja kaikki siihen liittyvä data koska Briar ei käytä palvelimia sinun tietojesi säilyttämiseen.</string>
|
<string name="startup_failed_service_error">Briar ei kyennyt käynnistämään vaadittua liitännäistä. Briarin uudelleenasennus yleensä korjaa ongelman. Huomaa kuitenkin, että tulet menettämään tilisi ja kaikki siihen liittyvä data koska Briar ei käytä palvelimia sinun tietojesi säilyttämiseen.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Tämä on Briarin testiversio. Sinun tilisi tulee vanhentumaan %d päivän päästä eikä sitä voi uusia.</item>
|
<item quantity="one">Tämä on Briarin testiversio. Sinun tilisi tulee vanhentumaan %d päivän päästä eikä sitä voi uusia.</item>
|
||||||
@@ -40,6 +43,9 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_update">Testiaikaa on pidennetty. Tilisi tulee nyt vanhentumaan %d päivän kuluttua.</string>
|
<string name="expiry_update">Testiaikaa on pidennetty. Tilisi tulee nyt vanhentumaan %d päivän kuluttua.</string>
|
||||||
<string name="expiry_date_reached">Tämä sovellus on vanhentunut.\nKiitos testaamisesta!</string>
|
<string name="expiry_date_reached">Tämä sovellus on vanhentunut.\nKiitos testaamisesta!</string>
|
||||||
|
<string name="download_briar">Jatkaaksesi Briarin käyttöä, lataa versio 1.0.</string>
|
||||||
|
<string name="create_new_account">Sinun täytyy luoda uusi tili, mutta voit käyttää samaa tunnusta.</string>
|
||||||
|
<string name="download_briar_button">Lataa Briar 1.0</string>
|
||||||
<string name="startup_open_database">Puretaan tietokannan salaus...</string>
|
<string name="startup_open_database">Puretaan tietokannan salaus...</string>
|
||||||
<string name="startup_migrate_database">Päivitetään tietokanta...</string>
|
<string name="startup_migrate_database">Päivitetään tietokanta...</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
@@ -98,6 +104,7 @@
|
|||||||
<string name="help">Ohje</string>
|
<string name="help">Ohje</string>
|
||||||
<string name="sorry">Pahoittelemme</string>
|
<string name="sorry">Pahoittelemme</string>
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
|
<string name="no_contacts">Ei yhteystietoja\n\nNapauta + nappia lisätäksesi yhteystiedon</string>
|
||||||
<string name="date_no_private_messages">Ei viestejä.</string>
|
<string name="date_no_private_messages">Ei viestejä.</string>
|
||||||
<string name="no_private_messages">Ei viestejä</string>
|
<string name="no_private_messages">Ei viestejä</string>
|
||||||
<string name="message_hint">Kirjoita viesti</string>
|
<string name="message_hint">Kirjoita viesti</string>
|
||||||
@@ -146,6 +153,7 @@
|
|||||||
<item quantity="other">%d uutta yhteystietoa lisätty.</item>
|
<item quantity="other">%d uutta yhteystietoa lisätty.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
|
<string name="groups_list_empty">Ei ryhmiä\n\nNapauta + nappia luodaksesi ryhmän tai pyydä yhteyshenkilöltä kutsua päästäksesi yhteen heidän ryhmistä.</string>
|
||||||
<string name="groups_created_by">Luonut %s</string>
|
<string name="groups_created_by">Luonut %s</string>
|
||||||
<plurals name="messages">
|
<plurals name="messages">
|
||||||
<item quantity="one">%d viesti</item>
|
<item quantity="one">%d viesti</item>
|
||||||
@@ -198,6 +206,7 @@
|
|||||||
<string name="groups_reveal_visible_revealed_by_contact">Yhteys käyttäjään on näkyvissä ryhmän jäsenille (käyttäjän %s paljastamana)</string>
|
<string name="groups_reveal_visible_revealed_by_contact">Yhteys käyttäjään on näkyvissä ryhmän jäsenille (käyttäjän %s paljastamana)</string>
|
||||||
<string name="groups_reveal_invisible">Yhteys käyttäjään ei ole näkyvissä ryhmän jäsenille</string>
|
<string name="groups_reveal_invisible">Yhteys käyttäjään ei ole näkyvissä ryhmän jäsenille</string>
|
||||||
<!--Forums-->
|
<!--Forums-->
|
||||||
|
<string name="no_forums">Ei foorumeita\n\nNapauta + nappia luodaksesi foorumin tai pyydä yhteyshenkilöltä kutsua päästäksesi yhteen heidän foorumeista</string>
|
||||||
<string name="create_forum_title">Luo foorumi</string>
|
<string name="create_forum_title">Luo foorumi</string>
|
||||||
<string name="choose_forum_hint">Valitse nimi foorumillesi</string>
|
<string name="choose_forum_hint">Valitse nimi foorumillesi</string>
|
||||||
<string name="create_forum_button">Luo foorumi</string>
|
<string name="create_forum_button">Luo foorumi</string>
|
||||||
@@ -214,18 +223,21 @@
|
|||||||
<string name="btn_reply">Vastaa</string>
|
<string name="btn_reply">Vastaa</string>
|
||||||
<string name="forum_leave">Lähde foorumista</string>
|
<string name="forum_leave">Lähde foorumista</string>
|
||||||
<string name="dialog_title_leave_forum">Vahvista foorumista lähteminen</string>
|
<string name="dialog_title_leave_forum">Vahvista foorumista lähteminen</string>
|
||||||
|
<string name="dialog_message_leave_forum">Oletko varma, että haluat lähteä tästä foorumista?\n\nKäyttäjät, jotka olet kutsunut tähän foorumiin, eivät välttämättä tule enää saamaan päivityksiä.</string>
|
||||||
<string name="dialog_button_leave">Lähde</string>
|
<string name="dialog_button_leave">Lähde</string>
|
||||||
<string name="forum_left_toast">Lähti foorumista</string>
|
<string name="forum_left_toast">Lähti foorumista</string>
|
||||||
<!--Forum Sharing-->
|
<!--Forum Sharing-->
|
||||||
<string name="forum_share_button">Jaa foorumi</string>
|
<string name="forum_share_button">Jaa foorumi</string>
|
||||||
<string name="contacts_selected">Yhteystiedot valittu</string>
|
<string name="contacts_selected">Yhteystiedot valittu</string>
|
||||||
<string name="activity_share_toolbar_header">Valitse yhteystiedot</string>
|
<string name="activity_share_toolbar_header">Valitse yhteystiedot</string>
|
||||||
|
<string name="no_contacts_selector">Ei yhteystietoja\n\nPalaa tänne, kun olet lisännyt yhteystiedon</string>
|
||||||
<string name="forum_shared_snackbar">Foorumi jaettu valittujen käyttäjien kanssa</string>
|
<string name="forum_shared_snackbar">Foorumi jaettu valittujen käyttäjien kanssa</string>
|
||||||
<string name="forum_share_message">Lisää viesti (valinnainen)</string>
|
<string name="forum_share_message">Lisää viesti (valinnainen)</string>
|
||||||
<string name="forum_share_error">Tämän foorumin jakamisessa tapahtui virhe.</string>
|
<string name="forum_share_error">Tämän foorumin jakamisessa tapahtui virhe.</string>
|
||||||
<string name="forum_invitation_received">%1$s on jakanut \"%2$s\" -nimisen foorumin kanssasi.</string>
|
<string name="forum_invitation_received">%1$s on jakanut \"%2$s\" -nimisen foorumin kanssasi.</string>
|
||||||
<string name="forum_invitation_sent">Olet jakanut \"%1$s\" -nimisen foorumin käyttäjälle %2$s.</string>
|
<string name="forum_invitation_sent">Olet jakanut \"%1$s\" -nimisen foorumin käyttäjälle %2$s.</string>
|
||||||
<string name="forum_invitations_title">Kutsut liittyä foorumeihin</string>
|
<string name="forum_invitations_title">Kutsut liittyä foorumeihin</string>
|
||||||
|
<string name="forum_invitation_exists">Olet jo hyväksynyt kutsun liittyä tähän foorumiin.\n\nUseamman kutsun hyväksyminen tekee foorumista nopeamman ja luotettavamman.</string>
|
||||||
<string name="forum_joined_toast">Liittyi foorumiin</string>
|
<string name="forum_joined_toast">Liittyi foorumiin</string>
|
||||||
<string name="forum_declined_toast">Kutsu hylätty</string>
|
<string name="forum_declined_toast">Kutsu hylätty</string>
|
||||||
<string name="shared_by_format">Jakanut %s</string>
|
<string name="shared_by_format">Jakanut %s</string>
|
||||||
@@ -252,6 +264,7 @@
|
|||||||
<string name="blogs_blog_post_received">Uusi blogikirjoitus vastaanotettu</string>
|
<string name="blogs_blog_post_received">Uusi blogikirjoitus vastaanotettu</string>
|
||||||
<string name="blogs_blog_post_scroll_to">Vieritä kohtaan</string>
|
<string name="blogs_blog_post_scroll_to">Vieritä kohtaan</string>
|
||||||
<string name="blogs_remove_blog">Poista blogi</string>
|
<string name="blogs_remove_blog">Poista blogi</string>
|
||||||
|
<string name="blogs_remove_blog_dialog_message">Oletko varma, että haluat poistaa tämän blogin?\n\nKirjoitukset poistuvat sinun laitteelta, mutta ei muiden laitteilta.\n\nKäyttäjät joiden kanssa olet jakanut tämän blogin eivät välttämättä saa uusia päivityksiä.</string>
|
||||||
<string name="blogs_remove_blog_ok">Poista</string>
|
<string name="blogs_remove_blog_ok">Poista</string>
|
||||||
<string name="blogs_blog_removed">Blogi poistettu</string>
|
<string name="blogs_blog_removed">Blogi poistettu</string>
|
||||||
<string name="blogs_reblog_comment_hint">Lisää kommentti (valinnainen)</string>
|
<string name="blogs_reblog_comment_hint">Lisää kommentti (valinnainen)</string>
|
||||||
@@ -281,8 +294,10 @@
|
|||||||
<string name="blogs_rss_feeds_manage_author">Tekijä:</string>
|
<string name="blogs_rss_feeds_manage_author">Tekijä:</string>
|
||||||
<string name="blogs_rss_feeds_manage_updated">Viimeksi päivitetty:</string>
|
<string name="blogs_rss_feeds_manage_updated">Viimeksi päivitetty:</string>
|
||||||
<string name="blogs_rss_remove_feed">Poista syöte</string>
|
<string name="blogs_rss_remove_feed">Poista syöte</string>
|
||||||
|
<string name="blogs_rss_remove_feed_dialog_message">Oletko varma, että haluat poistaa tämän syötteen?\n\nKirjoitukset poistuvat sinun laitteelta, mutta ei muiden laitteilta.\n\nKäyttäjät joiden kanssa olet jakanut tämän syötteen eivät välttämättä saa uusia päivityksiä.</string>
|
||||||
<string name="blogs_rss_remove_feed_ok">Poista</string>
|
<string name="blogs_rss_remove_feed_ok">Poista</string>
|
||||||
<string name="blogs_rss_feeds_manage_delete_error">Syötteen poistaminen epäonnistui!</string>
|
<string name="blogs_rss_feeds_manage_delete_error">Syötteen poistaminen epäonnistui!</string>
|
||||||
|
<string name="blogs_rss_feeds_manage_empty_state">Ei RSS syötteitä\n\nNapauta + nappia lisätäksesi syötteen</string>
|
||||||
<string name="blogs_rss_feeds_manage_error">Syötteiden lataamisessa tapahtui virhe. Yritä myöhemmin uudelleen.</string>
|
<string name="blogs_rss_feeds_manage_error">Syötteiden lataamisessa tapahtui virhe. Yritä myöhemmin uudelleen.</string>
|
||||||
<!--Settings Network-->
|
<!--Settings Network-->
|
||||||
<string name="network_settings_title">Verkot</string>
|
<string name="network_settings_title">Verkot</string>
|
||||||
@@ -370,5 +385,4 @@
|
|||||||
<string name="permission_camera_denied_toast">Kameralupaa ei myönnetty</string>
|
<string name="permission_camera_denied_toast">Kameralupaa ei myönnetty</string>
|
||||||
<string name="qr_code">QR-koodi</string>
|
<string name="qr_code">QR-koodi</string>
|
||||||
<string name="show_qr_code_fullscreen">Näytä QR-koodi koko näytöllä</string>
|
<string name="show_qr_code_fullscreen">Näytä QR-koodi koko näytöllä</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -393,7 +393,4 @@
|
|||||||
<string name="permission_camera_denied_toast">L’accès à la caméra n’a pas été accordé</string>
|
<string name="permission_camera_denied_toast">L’accès à la caméra n’a pas été accordé</string>
|
||||||
<string name="qr_code">Code QR</string>
|
<string name="qr_code">Code QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Afficher le code QR en plein écran</string>
|
<string name="show_qr_code_fullscreen">Afficher le code QR en plein écran</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Déconnecté de Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Vous avez été déconnecté en raison de mémoire insuffisante.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -128,5 +128,4 @@
|
|||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -41,18 +41,26 @@
|
|||||||
<string name="ongoing_notification_text">לחצו על מנת לפתוח את בריאר</string>
|
<string name="ongoing_notification_text">לחצו על מנת לפתוח את בריאר</string>
|
||||||
<plurals name="private_message_notification_text">
|
<plurals name="private_message_notification_text">
|
||||||
<item quantity="one">הודעה פרטית חדשה.</item>
|
<item quantity="one">הודעה פרטית חדשה.</item>
|
||||||
|
<item quantity="two">%d הודעות פריטות חדשות.</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%d הודעות פריטות חדשות.</item>
|
<item quantity="other">%d הודעות פריטות חדשות.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="group_message_notification_text">
|
<plurals name="group_message_notification_text">
|
||||||
<item quantity="one">הודעה קבוצתית חדשה.</item>
|
<item quantity="one">הודעה קבוצתית חדשה.</item>
|
||||||
|
<item quantity="two">%d הודעות קבוצתיות חדשות.</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%d הודעות קבוצתיות חדשות.</item>
|
<item quantity="other">%d הודעות קבוצתיות חדשות.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="forum_post_notification_text">
|
<plurals name="forum_post_notification_text">
|
||||||
<item quantity="one">פוסט חדש בפורומים.</item>
|
<item quantity="one">פוסט חדש בפורומים.</item>
|
||||||
|
<item quantity="two">%d פוסטים חדשים בפורומים.</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%d פוסטים חדשים בפורומים.</item>
|
<item quantity="other">%d פוסטים חדשים בפורומים.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="blog_post_notification_text">
|
<plurals name="blog_post_notification_text">
|
||||||
<item quantity="one">פוסט חדש בבלוגים.</item>
|
<item quantity="one">פוסט חדש בבלוגים.</item>
|
||||||
|
<item quantity="two">%d פוסטים חדשים בבלוגים.</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%d פוסטים חדשים בבלוגים.</item>
|
<item quantity="other">%d פוסטים חדשים בבלוגים.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Misc-->
|
<!--Misc-->
|
||||||
@@ -121,12 +129,16 @@
|
|||||||
<string name="introduction_response_declined_received_by_introducee">%1$s אומרים ש- %2$s סירבו להיות מוצגים בפניהם.</string>
|
<string name="introduction_response_declined_received_by_introducee">%1$s אומרים ש- %2$s סירבו להיות מוצגים בפניהם.</string>
|
||||||
<plurals name="introduction_notification_text">
|
<plurals name="introduction_notification_text">
|
||||||
<item quantity="one">נוסף איש קשר חדש.</item>
|
<item quantity="one">נוסף איש קשר חדש.</item>
|
||||||
|
<item quantity="two">נוספו %d אנשי קשר חדשים.</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">נוספו %d אנשי קשר חדשים.</item>
|
<item quantity="other">נוספו %d אנשי קשר חדשים.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Private Groups-->
|
<!--Private Groups-->
|
||||||
<string name="groups_created_by">נוצר על ידי %s</string>
|
<string name="groups_created_by">נוצר על ידי %s</string>
|
||||||
<plurals name="messages">
|
<plurals name="messages">
|
||||||
<item quantity="one">הודעה %d</item>
|
<item quantity="one">הודעה %d</item>
|
||||||
|
<item quantity="two">%d הודעות</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%d הודעות</item>
|
<item quantity="other">%d הודעות</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_group_is_empty">קבוצה זו הינה ריקה</string>
|
<string name="groups_group_is_empty">קבוצה זו הינה ריקה</string>
|
||||||
@@ -165,6 +177,8 @@
|
|||||||
<string name="groups_invitations_declined">הזמנה קבוצתית נדחתה</string>
|
<string name="groups_invitations_declined">הזמנה קבוצתית נדחתה</string>
|
||||||
<plurals name="groups_invitations_open">
|
<plurals name="groups_invitations_open">
|
||||||
<item quantity="one">הזמנה קבוצתית פתוחה %d</item>
|
<item quantity="one">הזמנה קבוצתית פתוחה %d</item>
|
||||||
|
<item quantity="two">%dהזמנות קבוצתית פתוחות </item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%dהזמנות קבוצתית פתוחות </item>
|
<item quantity="other">%dהזמנות קבוצתית פתוחות </item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="groups_invitations_response_accepted_sent">הסכמתם להזמנה הקבוצתית מ- %s.</string>
|
<string name="groups_invitations_response_accepted_sent">הסכמתם להזמנה הקבוצתית מ- %s.</string>
|
||||||
@@ -189,6 +203,8 @@
|
|||||||
<string name="no_posts">אין פוסטים</string>
|
<string name="no_posts">אין פוסטים</string>
|
||||||
<plurals name="posts">
|
<plurals name="posts">
|
||||||
<item quantity="one">פוסט %d</item>
|
<item quantity="one">פוסט %d</item>
|
||||||
|
<item quantity="two">%d פוסטים</item>
|
||||||
|
<item quantity="many"></item>
|
||||||
<item quantity="other">%d פוסטים</item>
|
<item quantity="other">%d פוסטים</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="forum_new_entry_posted">הפוסט נוצר</string>
|
<string name="forum_new_entry_posted">הפוסט נוצר</string>
|
||||||
@@ -235,5 +251,4 @@
|
|||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -354,5 +354,4 @@
|
|||||||
<string name="permission_camera_request_body">QR कोड को स्कैन करने के लिए, Briar को कैमरे तक पहुंच की आवश्यकता है।</string>
|
<string name="permission_camera_request_body">QR कोड को स्कैन करने के लिए, Briar को कैमरे तक पहुंच की आवश्यकता है।</string>
|
||||||
<string name="permission_camera_denied_body">आपने कैमरे तक पहुंच से वंचित किया है, लेकिन संपर्क जोड़ने के लिए कैमरे का उपयोग करने की आवश्यकता है। \ N \ n कृपया पहुंच प्रदान करने पर विचार करें।</string>
|
<string name="permission_camera_denied_body">आपने कैमरे तक पहुंच से वंचित किया है, लेकिन संपर्क जोड़ने के लिए कैमरे का उपयोग करने की आवश्यकता है। \ N \ n कृपया पहुंच प्रदान करने पर विचार करें।</string>
|
||||||
<string name="permission_camera_denied_toast">कैमरा अनुमति नहीं दी गई थी</string>
|
<string name="permission_camera_denied_toast">कैमरा अनुमति नहीं दी गई थी</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -393,7 +393,4 @@
|
|||||||
<string name="permission_camera_denied_toast">Autorizzazione fotocamera non concessa</string>
|
<string name="permission_camera_denied_toast">Autorizzazione fotocamera non concessa</string>
|
||||||
<string name="qr_code">Codice QR</string>
|
<string name="qr_code">Codice QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Mostra codice QR a tutto schermo</string>
|
<string name="show_qr_code_fullscreen">Mostra codice QR a tutto schermo</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Uscito da Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Uscito per mancanza di memoria</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -121,5 +121,4 @@
|
|||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -352,5 +352,4 @@
|
|||||||
<string name="permission_camera_request_body">For å skanne QR-koden, trenger Briar tilgang til kameraet.</string>
|
<string name="permission_camera_request_body">For å skanne QR-koden, trenger Briar tilgang til kameraet.</string>
|
||||||
<string name="permission_camera_denied_body">Du har nektet tilgang til kameraet, men tillegg av kontakter krever bruk av kameraet.\n\nOvervei å innvilge tilgang.</string>
|
<string name="permission_camera_denied_body">Du har nektet tilgang til kameraet, men tillegg av kontakter krever bruk av kameraet.\n\nOvervei å innvilge tilgang.</string>
|
||||||
<string name="permission_camera_denied_toast">Kameratilgang ble ikke innvilget</string>
|
<string name="permission_camera_denied_toast">Kameratilgang ble ikke innvilget</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<string name="setup_name_explanation">Je bijnaam wordt getoond bij alle content die je post. Nadat je account is aangemaakt is het niet mogelijk je bijnaam te wijzigen.</string>
|
<string name="setup_name_explanation">Je bijnaam wordt getoond bij alle content die je post. Nadat je account is aangemaakt is het niet mogelijk je bijnaam te wijzigen.</string>
|
||||||
<string name="setup_next">Volgende</string>
|
<string name="setup_next">Volgende</string>
|
||||||
<string name="setup_password_intro">Voer een wachtwoord in</string>
|
<string name="setup_password_intro">Voer een wachtwoord in</string>
|
||||||
<string name="setup_password_explanation">Je Briar-account is versleuteld opgeslagen op je apparaat, niet in de cloud. Als je je wachtwoord vergeet of Briar deïnstalleert is er geen manier om je account te herstellen.\n\nKies een lang wachtwoord dat moeilijk is om te raden , bijvoorbeeld vier willekeurige woorden of tien willekeurige letters, cijfers en symbolen.</string>
|
<string name="setup_password_explanation">Je Briar-account is versleuteld opgeslagen op je apparaat, niet in de cloud. Als je je wachtzin vergeet of Briar deïnstalleert is er geen manier om je account te herstellen.\n\nKies een lange wachtzin dat moeilijk is om te raden, bijvoorbeeld vier willekeurige woorden of tien willekeurige letters, cijfers en symbolen.</string>
|
||||||
<string name="setup_doze_title">Achtergrondverbindingen</string>
|
<string name="setup_doze_title">Achtergrondverbindingen</string>
|
||||||
<string name="setup_doze_intro">Om berichten te ontvangen dient Briar in de achtergrond verbonden te blijven.</string>
|
<string name="setup_doze_intro">Om berichten te ontvangen dient Briar in de achtergrond verbonden te blijven.</string>
|
||||||
<string name="setup_doze_explanation">Briar moet in de achtergrond verbonden blijven om berichten te ontvangen. Schakel batterij-optimalisaties a.u.b. uit zodat Briar verbonden kan blijven.</string>
|
<string name="setup_doze_explanation">Briar moet in de achtergrond verbonden blijven om berichten te ontvangen. Schakel batterij-optimalisaties a.u.b. uit zodat Briar verbonden kan blijven.</string>
|
||||||
@@ -43,6 +43,9 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_update">De verloopdatum voor de test is vooruitgeschoven. Je account verloopt nu binnen %d dagen.</string>
|
<string name="expiry_update">De verloopdatum voor de test is vooruitgeschoven. Je account verloopt nu binnen %d dagen.</string>
|
||||||
<string name="expiry_date_reached">Deze software is verlopen.\nBedankt vor het testen!</string>
|
<string name="expiry_date_reached">Deze software is verlopen.\nBedankt vor het testen!</string>
|
||||||
|
<string name="download_briar">Om Briar te blijven gebruiken, download a.u.b. versie 1.0.</string>
|
||||||
|
<string name="create_new_account">Je moet een nieuw account aanmaken. Je kan dezelfde bijnaam gebruiken.</string>
|
||||||
|
<string name="download_briar_button">Download Briar 1.0</string>
|
||||||
<string name="startup_open_database">Database aan het ontsleutelen…</string>
|
<string name="startup_open_database">Database aan het ontsleutelen…</string>
|
||||||
<string name="startup_migrate_database">Database aan het upgraden…</string>
|
<string name="startup_migrate_database">Database aan het upgraden…</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
@@ -125,12 +128,13 @@
|
|||||||
<string name="camera_error">Camerafout</string>
|
<string name="camera_error">Camerafout</string>
|
||||||
<string name="connecting_to_device">Aan het verbinden met apparaat\u2026</string>
|
<string name="connecting_to_device">Aan het verbinden met apparaat\u2026</string>
|
||||||
<string name="authenticating_with_device">Aan het authentificeren met apparaat\u2026</string>
|
<string name="authenticating_with_device">Aan het authentificeren met apparaat\u2026</string>
|
||||||
<string name="connection_aborted_local">Verbinding is verbroken! Dit kan betekenen dat iemand probeert te met je verbinding probeert te bemoeien</string>
|
<string name="connection_aborted_local">Verbinding is verbroken! Dit kan betekenen dat iemand probeert zich met je verbinding probeert te bemoeien.</string>
|
||||||
<string name="connection_aborted_remote">Verbinding is door je contact verbroken! Dit kan betekenen dat iemand met je verbinding probeert te bemoeien</string>
|
<string name="connection_aborted_remote">Verbinding is door je contact verbroken! Dit kan betekenen dat iemand met je verbinding probeert te bemoeien</string>
|
||||||
<!--Introductions-->
|
<!--Introductions-->
|
||||||
<string name="introduction_onboarding_title">Introduceer je contacten</string>
|
<string name="introduction_onboarding_title">Introduceer je contacten</string>
|
||||||
<string name="introduction_onboarding_text">Je kan je contacten aan elkaar introduceren zodat ze niet in levenden lijve elkaar te hoeven ontmoeten om op Briar in contact te komen.</string>
|
<string name="introduction_onboarding_text">Je kan je contacten aan elkaar introduceren zodat ze niet in levenden lijve elkaar te hoeven ontmoeten om op Briar in contact te komen.</string>
|
||||||
<string name="introduction_activity_title">Selecteer contact</string>
|
<string name="introduction_activity_title">Selecteer contact</string>
|
||||||
|
<string name="introduction_not_possible">Je bent al met een introductie bezig met deze contacten. Laat dit a.u.b. eerst voltooien. Als jij of je contact weinig online zijn, kan dit even duren.</string>
|
||||||
<string name="introduction_message_title">Intoduceer contacten</string>
|
<string name="introduction_message_title">Intoduceer contacten</string>
|
||||||
<string name="introduction_message_hint">Voeg een bericht toe (optioneel)</string>
|
<string name="introduction_message_hint">Voeg een bericht toe (optioneel)</string>
|
||||||
<string name="introduction_button">Introduceer</string>
|
<string name="introduction_button">Introduceer</string>
|
||||||
@@ -142,6 +146,7 @@
|
|||||||
<string name="introduction_request_exists_received">%1$s heeft gevraagd om je te introduceren aan %2$s, maar %2$s staat al in je contactenlijst. Omdat %1$s dit niet mag weten kun je nog steeds antwoorden:</string>
|
<string name="introduction_request_exists_received">%1$s heeft gevraagd om je te introduceren aan %2$s, maar %2$s staat al in je contactenlijst. Omdat %1$s dit niet mag weten kun je nog steeds antwoorden:</string>
|
||||||
<string name="introduction_request_answered_received">%1$s heeft gevraagd om je te introduceren aan %2$s.</string>
|
<string name="introduction_request_answered_received">%1$s heeft gevraagd om je te introduceren aan %2$s.</string>
|
||||||
<string name="introduction_response_accepted_sent">Je hebt de introductie aan %1$s geaccepteerd.</string>
|
<string name="introduction_response_accepted_sent">Je hebt de introductie aan %1$s geaccepteerd.</string>
|
||||||
|
<string name="introduction_response_accepted_sent_info">Voordat %1$s toegevoegd wordt aan je contacten, moeten ze de introductie accepteren. Dit kan even duren.</string>
|
||||||
<string name="introduction_response_declined_sent">Je hebt de introductie aan %1$s afgewezen.</string>
|
<string name="introduction_response_declined_sent">Je hebt de introductie aan %1$s afgewezen.</string>
|
||||||
<string name="introduction_response_accepted_received">%1$s heeft de introductie aan %2$sgeaccepteerd.</string>
|
<string name="introduction_response_accepted_received">%1$s heeft de introductie aan %2$sgeaccepteerd.</string>
|
||||||
<string name="introduction_response_declined_received">%1$s heeft de introductie aan %2$s afgewezen.</string>
|
<string name="introduction_response_declined_received">%1$s heeft de introductie aan %2$s afgewezen.</string>
|
||||||
@@ -352,8 +357,8 @@
|
|||||||
<string name="choose_ringtone_title">Kies ringtoon</string>
|
<string name="choose_ringtone_title">Kies ringtoon</string>
|
||||||
<string name="cannot_load_ringtone">Kan ringtoon niet laden</string>
|
<string name="cannot_load_ringtone">Kan ringtoon niet laden</string>
|
||||||
<!--Settings Feedback-->
|
<!--Settings Feedback-->
|
||||||
<string name="feedback_settings_title">Terugkoppeling</string>
|
<string name="feedback_settings_title">Feedback</string>
|
||||||
<string name="send_feedback">Verstuur terugkoppeling</string>
|
<string name="send_feedback">Verstuur feedback</string>
|
||||||
<!--Link Warning-->
|
<!--Link Warning-->
|
||||||
<string name="link_warning_title">Linkwaarschuwing</string>
|
<string name="link_warning_title">Linkwaarschuwing</string>
|
||||||
<string name="link_warning_intro">Je staat op het punt om de volgende link te open met een externe app.</string>
|
<string name="link_warning_intro">Je staat op het punt om de volgende link te open met een externe app.</string>
|
||||||
@@ -365,9 +370,9 @@
|
|||||||
<string name="not_your_fault">Dit is niet je schuld</string>
|
<string name="not_your_fault">Dit is niet je schuld</string>
|
||||||
<string name="please_send_report">Help ons a.u.b. om Briar te verbeteren door crashrapporten naar ons te sturen.</string>
|
<string name="please_send_report">Help ons a.u.b. om Briar te verbeteren door crashrapporten naar ons te sturen.</string>
|
||||||
<string name="report_is_encrypted">We beloven dat het rapport is versleuteld en veilig wordt verzonden.</string>
|
<string name="report_is_encrypted">We beloven dat het rapport is versleuteld en veilig wordt verzonden.</string>
|
||||||
<string name="feedback_title">Terugkoppeling</string>
|
<string name="feedback_title">Feedback</string>
|
||||||
<string name="describe_crash">Beschrijf wat er is gebeurd (optioneel)</string>
|
<string name="describe_crash">Beschrijf wat er is gebeurd (optioneel)</string>
|
||||||
<string name="enter_feedback">Voer je terugkoppeling in</string>
|
<string name="enter_feedback">Voer je feedback in</string>
|
||||||
<string name="optional_contact_email">Je e-mailadres (optioneel)</string>
|
<string name="optional_contact_email">Je e-mailadres (optioneel)</string>
|
||||||
<string name="include_debug_report_crash">Voeg geanonimiseerde gegevens toe over de crash.</string>
|
<string name="include_debug_report_crash">Voeg geanonimiseerde gegevens toe over de crash.</string>
|
||||||
<string name="include_debug_report_feedback">Voeg geanonimiseerde gegevens over dit apparaat toe.</string>
|
<string name="include_debug_report_feedback">Voeg geanonimiseerde gegevens over dit apparaat toe.</string>
|
||||||
@@ -388,7 +393,4 @@
|
|||||||
<string name="permission_camera_denied_toast">Cameratoegang niet vrijgegeven</string>
|
<string name="permission_camera_denied_toast">Cameratoegang niet vrijgegeven</string>
|
||||||
<string name="qr_code">QR-code</string>
|
<string name="qr_code">QR-code</string>
|
||||||
<string name="show_qr_code_fullscreen">Toon QR-code op volledig scherm</string>
|
<string name="show_qr_code_fullscreen">Toon QR-code op volledig scherm</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Uitgelogd van Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Uitgelogd door gebrek aan geheugen.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -344,6 +344,4 @@ Volètz suprimir vòstre compte e ne crear un nòu ?\n
|
|||||||
<string name="permission_camera_request_body">Per numerizar lo còdi QR cal que Briar aja l’accès a la camèra.</string>
|
<string name="permission_camera_request_body">Per numerizar lo còdi QR cal que Briar aja l’accès a la camèra.</string>
|
||||||
<string name="permission_camera_denied_toast">La permission a la camèra es pas estada donada</string>
|
<string name="permission_camera_denied_toast">La permission a la camèra es pas estada donada</string>
|
||||||
<string name="qr_code">Còdi QR</string>
|
<string name="qr_code">Còdi QR</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Desconnectat de Briar</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
<string name="introduction_message_title">Apresentar contatos</string>
|
<string name="introduction_message_title">Apresentar contatos</string>
|
||||||
<string name="introduction_message_hint">Adicione uma mensagem (opcional)</string>
|
<string name="introduction_message_hint">Adicione uma mensagem (opcional)</string>
|
||||||
<string name="introduction_button">Fazer apresentação</string>
|
<string name="introduction_button">Fazer apresentação</string>
|
||||||
<string name="introduction_sent">Sua Introdução foi enviada.</string>
|
<string name="introduction_sent">Sua apresentação foi enviada.</string>
|
||||||
<string name="introduction_error">Houve um erro ao fazer a apresentação</string>
|
<string name="introduction_error">Houve um erro ao fazer a apresentação</string>
|
||||||
<string name="introduction_response_error">Erro ao responder à apresentação</string>
|
<string name="introduction_response_error">Erro ao responder à apresentação</string>
|
||||||
<string name="introduction_request_sent">Você recebeu um pedido para apresentar %1$s a %2$s.</string>
|
<string name="introduction_request_sent">Você recebeu um pedido para apresentar %1$s a %2$s.</string>
|
||||||
@@ -391,7 +391,4 @@
|
|||||||
<string name="permission_camera_denied_toast">A permissão da câmera não foi concedida</string>
|
<string name="permission_camera_denied_toast">A permissão da câmera não foi concedida</string>
|
||||||
<string name="qr_code">Código QR</string>
|
<string name="qr_code">Código QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Mostrar o código QR na tela cheia</string>
|
<string name="show_qr_code_fullscreen">Mostrar o código QR na tela cheia</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Saiu do Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Saiu do Briar devido a falta de memória</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -114,6 +114,7 @@
|
|||||||
<string name="contact_deleted_toast">Contact șters</string>
|
<string name="contact_deleted_toast">Contact șters</string>
|
||||||
<!--Adding Contacts-->
|
<!--Adding Contacts-->
|
||||||
<string name="add_contact_title">Adaugă un contact</string>
|
<string name="add_contact_title">Adaugă un contact</string>
|
||||||
|
<string name="face_to_face">Trebuie să vă întâlniți cu persoana pe care doriți să o adăugați la contacte.\n\nAcest pas împiedică alte persoane să vă fure identitatea sau să vă citească mesajele în viitor.</string>
|
||||||
<string name="continue_button">Continuă</string>
|
<string name="continue_button">Continuă</string>
|
||||||
<string name="connection_failed">Conexiune eșuată</string>
|
<string name="connection_failed">Conexiune eșuată</string>
|
||||||
<string name="try_again_button">Încearcă din nou</string>
|
<string name="try_again_button">Încearcă din nou</string>
|
||||||
@@ -383,7 +384,4 @@
|
|||||||
<string name="permission_camera_denied_toast">Permisiunea de acces la camera foto nu a fost acordată</string>
|
<string name="permission_camera_denied_toast">Permisiunea de acces la camera foto nu a fost acordată</string>
|
||||||
<string name="qr_code">Cod QR</string>
|
<string name="qr_code">Cod QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Arată codul QR pe tot ecranul</string>
|
<string name="show_qr_code_fullscreen">Arată codul QR pe tot ecranul</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Ieșire din Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Ați ieșit din Briar din cauza lipsei memoriei</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -413,7 +413,4 @@
|
|||||||
<string name="permission_camera_denied_toast">Доступ к камере не был предоставлен</string>
|
<string name="permission_camera_denied_toast">Доступ к камере не был предоставлен</string>
|
||||||
<string name="qr_code">QR-код</string>
|
<string name="qr_code">QR-код</string>
|
||||||
<string name="show_qr_code_fullscreen">Показать QR-код во весь экран</string>
|
<string name="show_qr_code_fullscreen">Показать QR-код во весь экран</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">Выход из Briar</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">Выход из-за недостатка памяти.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -393,7 +393,4 @@
|
|||||||
<string name="permission_camera_denied_toast">S\’u dhanë leje mbi kamerën</string>
|
<string name="permission_camera_denied_toast">S\’u dhanë leje mbi kamerën</string>
|
||||||
<string name="qr_code">Kod QR</string>
|
<string name="qr_code">Kod QR</string>
|
||||||
<string name="show_qr_code_fullscreen">Shfaqe kodin QR sa tërë ekrani</string>
|
<string name="show_qr_code_fullscreen">Shfaqe kodin QR sa tërë ekrani</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
<string name="low_memory_shutdown_notification_title">U dol nga Briar-i</string>
|
|
||||||
<string name="low_memory_shutdown_notification_text">U dol për shkak mungese kujtese.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -289,5 +289,4 @@
|
|||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Detektovano je prekrivanje ekrana</string>
|
<string name="screen_filter_title">Detektovano je prekrivanje ekrana</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -148,5 +148,4 @@
|
|||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -311,5 +311,4 @@
|
|||||||
<string name="progress_title_logout">Briar\'dan çıkılıyor...</string>
|
<string name="progress_title_logout">Briar\'dan çıkılıyor...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -29,17 +29,22 @@
|
|||||||
<string name="sign_in_button">登录</string>
|
<string name="sign_in_button">登录</string>
|
||||||
<string name="forgotten_password">我忘记了密码</string>
|
<string name="forgotten_password">我忘记了密码</string>
|
||||||
<string name="dialog_title_lost_password">忘记密码</string>
|
<string name="dialog_title_lost_password">忘记密码</string>
|
||||||
<string name="dialog_message_lost_password">您的 Briar 账号被加密储存在您的设备上,而非云端,因此我们无法重置您的密码。您是否希望删除帐号,重新开始?\n\n注意:您的身份、联系人和消息将会永久遗失。</string>
|
<string name="dialog_message_lost_password">您的 Briar 账号被加密储存在您的设备上,而非云端,因此我们无法重置您的密码。您是否希望删除帐号,重新开始?\n\n注意:您的身份、联系人和消息将会永久丢失。</string>
|
||||||
<string name="startup_failed_notification_title">Briar 无法启动</string>
|
<string name="startup_failed_notification_title">Briar 无法启动</string>
|
||||||
<string name="startup_failed_notification_text">点击查看更多信息。</string>
|
<string name="startup_failed_notification_text">点击查看更多信息。</string>
|
||||||
<string name="startup_failed_activity_title">Briar 启动失败</string>
|
<string name="startup_failed_activity_title">Briar 启动失败</string>
|
||||||
|
<string name="startup_failed_db_error">由于一些原因,Briar 数据库已损坏并且无法修复。您的帐户、数据和所有联系人已经丢失。不幸的是,您需要重新安装 Briar 或者在提示输入密码时选择“我忘记了密码”以重新创建一个 Briar 帐户。</string>
|
||||||
|
<string name="startup_failed_data_too_old_error">您的帐户由旧版本应用创建,无法在此版本上打开。您需要重新安装旧版本应用或在提示输入密码时选择“我忘记了密码”以创建新帐户。</string>
|
||||||
<string name="startup_failed_data_too_new_error">该应用版本过旧。请升级至最新版本并重试。</string>
|
<string name="startup_failed_data_too_new_error">该应用版本过旧。请升级至最新版本并重试。</string>
|
||||||
<string name="startup_failed_service_error">Briar 无法开启一个必要插件。通常情况下,重新安装 Briar 可以解决这个问题。但是由于 Briar 并不采用中央服务器来储存您的数据,您将丢失您的账号和与您的账号相关的一切数据。</string>
|
<string name="startup_failed_service_error">Briar 无法开启一个必要插件。通常情况下,重新安装 Briar 可以解决这个问题。但是由于 Briar 并不采用中央服务器来储存您的数据,您将丢失您的账号和与您的账号相关的一切数据。</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="other">这是 Briar 的一个测试版本。您的帐户将在 %d 天后过期,且无法继续使用。</item>
|
<item quantity="other">这是 Briar 的一个测试版本。您的帐户将在 %d 天后过期,且逾期后无法继续使用。</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_update">测试到期时间延长,您的帐户将在 %d 天后过期。</string>
|
<string name="expiry_update">测试到期时间延长,您的帐户将在 %d 天后过期。</string>
|
||||||
<string name="expiry_date_reached">本软件已过期。\n感谢您的测试!</string>
|
<string name="expiry_date_reached">本软件已过期。\n感谢您的测试!</string>
|
||||||
|
<string name="download_briar">如想继续使用 Briar,请下载 1.0 版。</string>
|
||||||
|
<string name="create_new_account">你需要创建一个新账户,但不能使用相同的昵称。</string>
|
||||||
|
<string name="download_briar_button">下载 Briar 1.0</string>
|
||||||
<string name="startup_open_database">正在解密数据库……</string>
|
<string name="startup_open_database">正在解密数据库……</string>
|
||||||
<string name="startup_migrate_database">正在升级数据库……</string>
|
<string name="startup_migrate_database">正在升级数据库……</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
@@ -94,11 +99,13 @@
|
|||||||
<string name="help">帮助</string>
|
<string name="help">帮助</string>
|
||||||
<string name="sorry">抱歉</string>
|
<string name="sorry">抱歉</string>
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="date_no_private_messages">没有消息。</string>
|
<string name="no_contacts">没有联系人\n\n点击 + 号添加</string>
|
||||||
|
<string name="date_no_private_messages">无消息。</string>
|
||||||
|
<string name="no_private_messages">没有消息</string>
|
||||||
<string name="message_hint">键入信息</string>
|
<string name="message_hint">键入信息</string>
|
||||||
<string name="delete_contact">删除联系人</string>
|
<string name="delete_contact">删除联系人</string>
|
||||||
<string name="dialog_title_delete_contact">确认删除联系人</string>
|
<string name="dialog_title_delete_contact">确认删除联系人</string>
|
||||||
<string name="dialog_message_delete_contact">确认要删除该联系人和与之交流的所有消息吗?</string>
|
<string name="dialog_message_delete_contact">确认要删除该联系人和所有聊天记录吗?</string>
|
||||||
<string name="contact_deleted_toast">联系人已删除</string>
|
<string name="contact_deleted_toast">联系人已删除</string>
|
||||||
<!--Adding Contacts-->
|
<!--Adding Contacts-->
|
||||||
<string name="add_contact_title">添加联系人</string>
|
<string name="add_contact_title">添加联系人</string>
|
||||||
@@ -112,7 +119,7 @@
|
|||||||
<string name="contact_already_exists">联系人 %s 已存在</string>
|
<string name="contact_already_exists">联系人 %s 已存在</string>
|
||||||
<string name="contact_exchange_failed">联系人交换失败</string>
|
<string name="contact_exchange_failed">联系人交换失败</string>
|
||||||
<string name="qr_code_invalid">二维码无效</string>
|
<string name="qr_code_invalid">二维码无效</string>
|
||||||
<string name="qr_code_unsupported">您正在扫描的是来自 %s 版旧版本的二维码,目前不再支持。\n\n请确保你们两人都在运行最新版本并重试。</string>
|
<string name="qr_code_unsupported">您正在扫描的是来自旧版本 %s 版的二维码,目前不再支持。\n\n请确保你们两人都在运行最新版本并重试。</string>
|
||||||
<string name="camera_error">摄像头出错</string>
|
<string name="camera_error">摄像头出错</string>
|
||||||
<string name="connecting_to_device">正在连接至设备\u2026</string>
|
<string name="connecting_to_device">正在连接至设备\u2026</string>
|
||||||
<string name="authenticating_with_device">正在验证设备\u2026</string>
|
<string name="authenticating_with_device">正在验证设备\u2026</string>
|
||||||
@@ -122,6 +129,7 @@
|
|||||||
<string name="introduction_onboarding_title">介绍您的联系人</string>
|
<string name="introduction_onboarding_title">介绍您的联系人</string>
|
||||||
<string name="introduction_onboarding_text">您可以互相介绍联系人,这样他们可以直接在 Briar 上建立联系而不必亲自见面。</string>
|
<string name="introduction_onboarding_text">您可以互相介绍联系人,这样他们可以直接在 Briar 上建立联系而不必亲自见面。</string>
|
||||||
<string name="introduction_activity_title">选择联系人</string>
|
<string name="introduction_activity_title">选择联系人</string>
|
||||||
|
<string name="introduction_not_possible">您当前正给这些联系人交换名片。请先等待交换完成。如果您或您的好友很少在线,那需要花些时间。</string>
|
||||||
<string name="introduction_message_title">介绍联系人</string>
|
<string name="introduction_message_title">介绍联系人</string>
|
||||||
<string name="introduction_message_hint">添加一句话 (选填)</string>
|
<string name="introduction_message_hint">添加一句话 (选填)</string>
|
||||||
<string name="introduction_button">完成介绍</string>
|
<string name="introduction_button">完成介绍</string>
|
||||||
@@ -352,5 +360,4 @@
|
|||||||
<string name="permission_camera_request_body">Briar 需要获得相机权限以扫描二维码。</string>
|
<string name="permission_camera_request_body">Briar 需要获得相机权限以扫描二维码。</string>
|
||||||
<string name="permission_camera_denied_body">您拒绝了相机权限,而添加联系人需要使用相机\n\n请考虑授予相机权限。</string>
|
<string name="permission_camera_denied_body">您拒绝了相机权限,而添加联系人需要使用相机\n\n请考虑授予相机权限。</string>
|
||||||
<string name="permission_camera_denied_toast">未授予相机权限</string>
|
<string name="permission_camera_denied_toast">未授予相机权限</string>
|
||||||
<!--Low Memory Notification-->
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<color name="briar_blue">#2D3E50</color>
|
<color name="briar_blue">#2D3E50</color>
|
||||||
<color name="briar_blue_dark">#0F1720</color>
|
<color name="briar_blue_dark">#0F1720</color>
|
||||||
|
<color name="briar_blue_light">#4F6C8C</color>
|
||||||
<color name="briar_gold">#FCCF1C</color>
|
<color name="briar_gold">#FCCF1C</color>
|
||||||
<color name="briar_green_light">#95D220</color>
|
<color name="briar_green_light">#95D220</color>
|
||||||
|
<color name="briar_link">#06B9FF</color>
|
||||||
|
|
||||||
<color name="window_background">#eceff1</color>
|
<color name="window_background">#eceff1</color>
|
||||||
<color name="action_bar_text">#FFFFFF</color>
|
<color name="action_bar_text">#FFFFFF</color>
|
||||||
@@ -19,23 +21,20 @@
|
|||||||
<color name="control_normal_light">#757575</color>
|
<color name="control_normal_light">#757575</color>
|
||||||
|
|
||||||
<!-- text colors -->
|
<!-- text colors -->
|
||||||
<color name="briar_text_link">#06b9ff</color>
|
<color name="briar_text_link">@color/briar_link</color>
|
||||||
<color name="briar_text_primary">#df000000</color>
|
<color name="briar_text_primary">#df000000</color>
|
||||||
<color name="briar_text_primary_inverse">#ffffff</color>
|
<color name="briar_text_primary_inverse">#ffffff</color>
|
||||||
<color name="briar_text_secondary">#8a000000</color>
|
<color name="briar_text_secondary">#8a000000</color>
|
||||||
<color name="briar_text_secondary_inverse">#b4ffffff</color>
|
<color name="briar_text_secondary_inverse">#b4ffffff</color>
|
||||||
<color name="briar_text_tertiary">#61000000</color>
|
<color name="briar_text_tertiary">#61000000</color>
|
||||||
<color name="briar_text_tertiary_inverse">#80ffffff</color>
|
<color name="briar_text_tertiary_inverse">#80ffffff</color>
|
||||||
<color name="briar_button_positive">#06b9ff</color>
|
<color name="briar_button_positive">@color/briar_link</color>
|
||||||
<color name="briar_button_negative">#ff0000</color>
|
<color name="briar_button_negative">#ff0000</color>
|
||||||
<color name="briar_warning_background">#ff0000</color>
|
<color name="briar_warning_background">#ff0000</color>
|
||||||
<color name="emoji_text_color">#ff000000</color>
|
<color name="emoji_text_color">#ff000000</color>
|
||||||
|
|
||||||
<color name="emoji_pager_background">@color/window_background</color>
|
<color name="emoji_pager_background">@color/window_background</color>
|
||||||
|
|
||||||
<!-- this is needed as preference_category_material layout uses this color as the text color -->
|
|
||||||
<color name="preference_fallback_accent_color">@color/briar_accent</color>
|
|
||||||
|
|
||||||
<color name="thread_indicator">#9e9e9e</color>
|
<color name="thread_indicator">#9e9e9e</color>
|
||||||
<color name="divider">#c1c1c1</color>
|
<color name="divider">#c1c1c1</color>
|
||||||
<color name="menu_background">#FFFFFF</color>
|
<color name="menu_background">#FFFFFF</color>
|
||||||
|
|||||||
@@ -9,10 +9,7 @@
|
|||||||
<item name="android:textColorLink">@color/briar_text_link</item>
|
<item name="android:textColorLink">@color/briar_text_link</item>
|
||||||
<item name="android:windowBackground">@color/window_background</item>
|
<item name="android:windowBackground">@color/window_background</item>
|
||||||
<item name="android:windowAnimationStyle">@style/ActivityAnimation</item>
|
<item name="android:windowAnimationStyle">@style/ActivityAnimation</item>
|
||||||
|
|
||||||
<!-- These fix a long-standing UI bug in the support preference library -->
|
|
||||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||||
<item name="android:listSeparatorTextViewStyle">@style/BriarTheme.ListSeparatorTextView</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="BriarTheme.NoActionBar" parent="BriarTheme">
|
<style name="BriarTheme.NoActionBar" parent="BriarTheme">
|
||||||
@@ -56,13 +53,4 @@
|
|||||||
<item name="buttonBarNeutralButtonStyle">@style/Widget.AppCompat.Button.Borderless</item>
|
<item name="buttonBarNeutralButtonStyle">@style/Widget.AppCompat.Button.Borderless</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- This fixes a UI bug in the support preference library -->
|
|
||||||
<style name="BriarTheme.ListSeparatorTextView">
|
|
||||||
<item name="android:textSize">14sp</item>
|
|
||||||
<item name="android:textStyle">bold</item>
|
|
||||||
<item name="android:textColor">@color/briar_accent</item>
|
|
||||||
<item name="android:paddingTop">16dp</item>
|
|
||||||
<item name="android:layout_marginBottom">16dp</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/preferences_category"
|
||||||
android:title="@string/network_settings_title">
|
android:title="@string/network_settings_title">
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
@@ -25,9 +26,8 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:layout="@layout/divider_preference"/>
|
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/preferences_category"
|
||||||
android:title="@string/security_settings_title">
|
android:title="@string/security_settings_title">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
@@ -41,9 +41,8 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:layout="@layout/divider_preference"/>
|
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/preferences_category"
|
||||||
android:title="@string/panic_setting_title">
|
android:title="@string/panic_setting_title">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
@@ -58,9 +57,8 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:layout="@layout/divider_preference"/>
|
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/preferences_category"
|
||||||
android:title="@string/notification_settings_title">
|
android:title="@string/notification_settings_title">
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
@@ -111,24 +109,31 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:layout="@layout/divider_preference"/>
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/preferences_category"
|
||||||
|
android:title="@string/feedback_settings_title"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="pref_key_send_feedback"
|
||||||
|
android:title="@string/send_feedback"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/feedback_settings_title">
|
android:layout="@layout/preferences_category"
|
||||||
|
android:title="Testing">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="pref_key_send_feedback"
|
android:key="pref_key_test_data"
|
||||||
android:title="@string/send_feedback"/>
|
android:title="Create Test Data">
|
||||||
|
|
||||||
|
<intent
|
||||||
|
android:targetClass="org.briarproject.briar.android.test.TestDataActivity"
|
||||||
|
android:targetPackage="@string/app_package"/>
|
||||||
|
</Preference>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="pref_key_explode"
|
||||||
|
android:title="Crash"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="pref_key_test_data"
|
|
||||||
android:title="Create Test Data">
|
|
||||||
|
|
||||||
<intent
|
|
||||||
android:targetClass="org.briarproject.briar.android.test.TestDataActivity"
|
|
||||||
android:targetPackage="@string/app_package"/>
|
|
||||||
</Preference>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|||||||
@@ -5,8 +5,12 @@ import android.app.Application;
|
|||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class only exists to avoid static initialisation of ACRA
|
* This class only exists to avoid static initialisation of ACRA
|
||||||
*/
|
*/
|
||||||
@@ -34,6 +38,11 @@ public class TestBriarApplication extends Application
|
|||||||
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<LogRecord> getRecentLogRecords() {
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AndroidComponent getApplicationComponent() {
|
public AndroidComponent getApplicationComponent() {
|
||||||
return applicationComponent;
|
return applicationComponent;
|
||||||
|
|||||||
@@ -2,18 +2,20 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-api', configuration: 'default')
|
implementation project(path: ':bramble-api', configuration: 'default')
|
||||||
|
|
||||||
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
useJava6StandardLibrary(it)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'net.ltgt.apt'
|
apply plugin: 'net.ltgt.apt'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
@@ -27,6 +28,8 @@ dependencies {
|
|||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -46,6 +49,9 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
'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.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.jdom:jdom2:2.0.6:jdom2-2.0.6.jar:1345f11ba606d15603d6740551a8c21947c0215640770ec67271fe78bea97cf5',
|
'org.jdom:jdom2:2.0.6:jdom2-2.0.6.jar:1345f11ba606d15603d6740551a8c21947c0215640770ec67271fe78bea97cf5',
|
||||||
@@ -55,12 +61,8 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.jsoup:jsoup:1.10.3:jsoup-1.10.3.jar:a0784e793d7f518eb1defb47b428da011cd483c5da32d49c569bf491e4f1579a',
|
'org.jsoup:jsoup:1.10.3:jsoup-1.10.3.jar:a0784e793d7f518eb1defb47b428da011cd483c5da32d49c569bf491e4f1579a',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
'org.slf4j:slf4j-api:1.7.16:slf4j-api-1.7.16.jar:e56288031f5e60652c06e7bb6e9fa410a61231ab54890f7b708fc6adc4107c5b',
|
'org.slf4j:slf4j-api:1.7.16:slf4j-api-1.7.16.jar:e56288031f5e60652c06e7bb6e9fa410a61231ab54890f7b708fc6adc4107c5b',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
useJava6StandardLibrary(it)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -453,12 +453,11 @@ class IntroduceeProtocolEngine
|
|||||||
.getContact(txn, s.getRemote().author.getId(),
|
.getContact(txn, s.getRemote().author.getId(),
|
||||||
localAuthor.getId());
|
localAuthor.getId());
|
||||||
|
|
||||||
// bind the keys to the new contact
|
// add the keys to the new contact
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
keys = keyManager
|
keys = keyManager
|
||||||
.addUnboundKeys(txn, new SecretKey(s.getMasterKey()),
|
.addContact(txn, c.getId(), new SecretKey(s.getMasterKey()),
|
||||||
timestamp, s.getLocal().alice);
|
timestamp, s.getLocal().alice, false);
|
||||||
keyManager.bindKeys(txn, c.getId(), keys);
|
|
||||||
|
|
||||||
// add signed transport properties for the contact
|
// add signed transport properties for the contact
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public class MessagingModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
PrivateMessageFactory providePrivateMessageFactory(
|
PrivateMessageFactory providePrivateMessageFactory(
|
||||||
ClientHelper clientHelper) {
|
PrivateMessageFactoryImpl privateMessageFactory) {
|
||||||
return new PrivateMessageFactoryImpl(clientHelper);
|
return privateMessageFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void createTestData(int numContacts, int numPrivateMsgs,
|
public void createTestData(int numContacts, int numPrivateMsgs,
|
||||||
int numBlogPosts, int numForums, int numForumPosts) {
|
int numBlogPosts, int numForums, int numForumPosts) {
|
||||||
if (numContacts == 0)
|
if (numContacts == 0)
|
||||||
@@ -216,8 +217,12 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
|
|
||||||
// LAN
|
// LAN
|
||||||
TransportProperties lan = new TransportProperties();
|
TransportProperties lan = new TransportProperties();
|
||||||
String lanAddress = getRandomLanAddress();
|
StringBuilder sb = new StringBuilder();
|
||||||
lan.put(LanTcpConstants.PROP_IP_PORTS, lanAddress);
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (sb.length() > 0) sb.append(',');
|
||||||
|
sb.append(getRandomLanAddress());
|
||||||
|
}
|
||||||
|
lan.put(LanTcpConstants.PROP_IP_PORTS, sb.toString());
|
||||||
props.put(LanTcpConstants.ID, lan);
|
props.put(LanTcpConstants.ID, lan);
|
||||||
|
|
||||||
// Tor
|
// Tor
|
||||||
@@ -250,8 +255,14 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
private String getRandomLanAddress() {
|
private String getRandomLanAddress() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
// address
|
// address
|
||||||
for (int i = 0; i < 4; i++) {
|
if (random.nextInt(5) == 0) {
|
||||||
if (sb.length() > 0) sb.append(".");
|
sb.append("10.");
|
||||||
|
sb.append(random.nextInt(2)).append('.');
|
||||||
|
sb.append(random.nextInt(2)).append('.');
|
||||||
|
sb.append(random.nextInt(256));
|
||||||
|
} else {
|
||||||
|
sb.append("192.168.");
|
||||||
|
sb.append(random.nextInt(2)).append('.');
|
||||||
sb.append(random.nextInt(256));
|
sb.append(random.nextInt(256));
|
||||||
}
|
}
|
||||||
// port
|
// port
|
||||||
@@ -264,7 +275,7 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
// address
|
// address
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
if (random.nextBoolean()) sb.append(2 + random.nextInt(5));
|
if (random.nextBoolean()) sb.append(2 + random.nextInt(6));
|
||||||
else sb.append((char) (random.nextInt(26) + 'a'));
|
else sb.append((char) (random.nextInt(26) + 'a'));
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
|||||||
@@ -66,12 +66,17 @@ interface IntroductionIntegrationTestComponent
|
|||||||
void inject(IntroductionIntegrationTest init);
|
void inject(IntroductionIntegrationTest init);
|
||||||
|
|
||||||
void inject(MessageEncoderParserIntegrationTest init);
|
void inject(MessageEncoderParserIntegrationTest init);
|
||||||
|
|
||||||
void inject(SessionEncoderParserIntegrationTest init);
|
void inject(SessionEncoderParserIntegrationTest init);
|
||||||
|
|
||||||
void inject(IntroductionCryptoIntegrationTest init);
|
void inject(IntroductionCryptoIntegrationTest init);
|
||||||
|
|
||||||
MessageEncoder getMessageEncoder();
|
MessageEncoder getMessageEncoder();
|
||||||
|
|
||||||
MessageParser getMessageParser();
|
MessageParser getMessageParser();
|
||||||
|
|
||||||
SessionParser getSessionParser();
|
SessionParser getSessionParser();
|
||||||
|
|
||||||
IntroductionCrypto getIntroductionCrypto();
|
IntroductionCrypto getIntroductionCrypto();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager
|
|||||||
import org.briarproject.briar.blog.BlogModule;
|
import org.briarproject.briar.blog.BlogModule;
|
||||||
import org.briarproject.briar.client.BriarClientModule;
|
import org.briarproject.briar.client.BriarClientModule;
|
||||||
import org.briarproject.briar.forum.ForumModule;
|
import org.briarproject.briar.forum.ForumModule;
|
||||||
import org.briarproject.briar.introduction.IntroductionCryptoIntegrationTest;
|
|
||||||
import org.briarproject.briar.introduction.IntroductionModule;
|
import org.briarproject.briar.introduction.IntroductionModule;
|
||||||
import org.briarproject.briar.introduction.MessageEncoderParserIntegrationTest;
|
|
||||||
import org.briarproject.briar.introduction.SessionEncoderParserIntegrationTest;
|
|
||||||
import org.briarproject.briar.messaging.MessagingModule;
|
import org.briarproject.briar.messaging.MessagingModule;
|
||||||
import org.briarproject.briar.privategroup.PrivateGroupModule;
|
import org.briarproject.briar.privategroup.PrivateGroupModule;
|
||||||
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
||||||
|
|||||||
25
build.gradle
25
build.gradle
@@ -22,30 +22,7 @@ buildscript {
|
|||||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||||
classpath 'net.ltgt.gradle:gradle-apt-plugin:0.9'
|
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.2.0'
|
||||||
|
classpath 'ru.vyarus:gradle-animalsniffer-plugin:1.4.3'
|
||||||
classpath files('libs/gradle-witness.jar')
|
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"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a jar containing the java.lang.invoke classes for the Java 6 bootstrap classpath
|
|
||||||
task createJavaLangInvokeJar(type: Zip) {
|
|
||||||
archiveName 'invoke.jar'
|
|
||||||
destinationDir file("${project.rootDir}/build")
|
|
||||||
from zipTree("${System.getProperty('java.home')}/lib/rt.jar").matching {
|
|
||||||
include 'java/lang/invoke/*'
|
|
||||||
}
|
|
||||||
include '**/*'
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user