Compare commits

..

1 Commits

Author SHA1 Message Date
akwizgran
934997ed91 Check for partial setup of clients due to feature flags reverting. 2023-01-31 11:23:19 +00:00
102 changed files with 869 additions and 1832 deletions

View File

@@ -83,8 +83,7 @@ android test:
test_reproducible: test_reproducible:
stage: check_reproducibility stage: check_reproducibility
script: script:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=\"briar ${CI_COMMIT_REF_NAME}\" https://code.briarproject.org/api/v4/projects/61/trigger/pipeline" - "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
- "curl -X POST -F token=${RELEASE_JAR_CHECK_TOKEN} -F ref=main -F variables[RELEASE_TAG]=\"briar-headless ${CI_COMMIT_REF_NAME}\" https://code.briarproject.org/api/v4/projects/307/trigger/pipeline"
only: only:
- tags - tags

View File

@@ -13,8 +13,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 31 targetSdkVersion 31
versionCode 10422 versionCode 10420
versionName "1.4.22" versionName "1.4.20"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -16,7 +16,6 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@Immutable @Immutable
@@ -24,24 +23,17 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOC
public abstract class BdfMessageValidator implements MessageValidator { public abstract class BdfMessageValidator implements MessageValidator {
protected static final Logger LOG = protected static final Logger LOG =
getLogger(BdfMessageValidator.class.getName()); Logger.getLogger(BdfMessageValidator.class.getName());
protected final ClientHelper clientHelper; protected final ClientHelper clientHelper;
protected final MetadataEncoder metadataEncoder; protected final MetadataEncoder metadataEncoder;
protected final Clock clock; protected final Clock clock;
protected final boolean canonical;
protected BdfMessageValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock, boolean canonical) {
this.clientHelper = clientHelper;
this.metadataEncoder = metadataEncoder;
this.clock = clock;
this.canonical = canonical;
}
protected BdfMessageValidator(ClientHelper clientHelper, protected BdfMessageValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) { MetadataEncoder metadataEncoder, Clock clock) {
this(clientHelper, metadataEncoder, clock, true); this.clientHelper = clientHelper;
this.metadataEncoder = metadataEncoder;
this.clock = clock;
} }
protected abstract BdfMessageContext validateMessage(Message m, Group g, protected abstract BdfMessageContext validateMessage(Message m, Group g,
@@ -57,7 +49,7 @@ public abstract class BdfMessageValidator implements MessageValidator {
"Timestamp is too far in the future"); "Timestamp is too far in the future");
} }
try { try {
BdfList bodyList = clientHelper.toList(m, canonical); BdfList bodyList = clientHelper.toList(m.getBody());
BdfMessageContext result = validateMessage(m, g, bodyList); BdfMessageContext result = validateMessage(m, g, bodyList);
Metadata meta = metadataEncoder.encode(result.getDictionary()); Metadata meta = metadataEncoder.encode(result.getDictionary());
return new MessageContext(meta, result.getDependencies()); return new MessageContext(meta, result.getDependencies());

View File

@@ -49,9 +49,6 @@ public interface ClientHelper {
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException, BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException; FormatException;
BdfList getMessageAsList(Transaction txn, MessageId m, boolean canonical)
throws DbException, FormatException;
BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException, BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
FormatException; FormatException;
@@ -109,8 +106,6 @@ public interface ClientHelper {
BdfList toList(Message m) throws FormatException; BdfList toList(Message m) throws FormatException;
BdfList toList(Message m, boolean canonical) throws FormatException;
BdfList toList(Author a); BdfList toList(Author a);
byte[] sign(String label, BdfList toSign, PrivateKey privateKey) byte[] sign(String label, BdfList toSign, PrivateKey privateKey)

View File

@@ -11,7 +11,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe @NotThreadSafe
public final class BdfDictionary extends TreeMap<String, Object> { public class BdfDictionary extends TreeMap<String, Object> {
public static final Object NULL_VALUE = new Object(); public static final Object NULL_VALUE = new Object();
@@ -39,9 +39,9 @@ public final class BdfDictionary extends TreeMap<String, Object> {
} }
public Boolean getBoolean(String key) throws FormatException { public Boolean getBoolean(String key) throws FormatException {
Boolean value = getOptionalBoolean(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof Boolean) return (Boolean) o;
return value; throw new FormatException();
} }
@Nullable @Nullable
@@ -52,16 +52,19 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public Boolean getBoolean(String key, Boolean defaultValue) public Boolean getBoolean(String key, Boolean defaultValue) {
throws FormatException { Object o = get(key);
Boolean value = getOptionalBoolean(key); if (o instanceof Boolean) return (Boolean) o;
return value == null ? defaultValue : value; return defaultValue;
} }
public Long getLong(String key) throws FormatException { public Long getLong(String key) throws FormatException {
Long value = getOptionalLong(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof Long) return (Long) o;
return value; if (o instanceof Integer) return ((Integer) o).longValue();
if (o instanceof Short) return ((Short) o).longValue();
if (o instanceof Byte) return ((Byte) o).longValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -75,37 +78,20 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public Long getLong(String key, Long defaultValue) throws FormatException { public Long getLong(String key, Long defaultValue) {
Long value = getOptionalLong(key); Object o = get(key);
return value == null ? defaultValue : value; if (o instanceof Long) return (Long) o;
} if (o instanceof Integer) return ((Integer) o).longValue();
if (o instanceof Short) return ((Short) o).longValue();
public Integer getInt(String key) throws FormatException { if (o instanceof Byte) return ((Byte) o).longValue();
Integer value = getOptionalInt(key); return defaultValue;
if (value == null) throw new FormatException();
return value;
}
@Nullable
public Integer getOptionalInt(String key) throws FormatException {
Long value = getOptionalLong(key);
if (value == null) return null;
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new FormatException();
}
return value.intValue();
}
public Integer getInt(String key, Integer defaultValue)
throws FormatException {
Integer value = getOptionalInt(key);
return value == null ? defaultValue : value;
} }
public Double getDouble(String key) throws FormatException { public Double getDouble(String key) throws FormatException {
Double value = getOptionalDouble(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof Double) return (Double) o;
return value; if (o instanceof Float) return ((Float) o).doubleValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -117,16 +103,17 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public Double getDouble(String key, Double defaultValue) public Double getDouble(String key, Double defaultValue) {
throws FormatException { Object o = get(key);
Double value = getOptionalDouble(key); if (o instanceof Double) return (Double) o;
return value == null ? defaultValue : value; if (o instanceof Float) return ((Float) o).doubleValue();
return defaultValue;
} }
public String getString(String key) throws FormatException { public String getString(String key) throws FormatException {
String value = getOptionalString(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof String) return (String) o;
return value; throw new FormatException();
} }
@Nullable @Nullable
@@ -137,16 +124,17 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public String getString(String key, String defaultValue) public String getString(String key, String defaultValue) {
throws FormatException { Object o = get(key);
String value = getOptionalString(key); if (o instanceof String) return (String) o;
return value == null ? defaultValue : value; return defaultValue;
} }
public byte[] getRaw(String key) throws FormatException { public byte[] getRaw(String key) throws FormatException {
byte[] value = getOptionalRaw(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof byte[]) return (byte[]) o;
return value; if (o instanceof Bytes) return ((Bytes) o).getBytes();
throw new FormatException();
} }
@Nullable @Nullable
@@ -158,16 +146,17 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public byte[] getRaw(String key, byte[] defaultValue) public byte[] getRaw(String key, byte[] defaultValue) {
throws FormatException { Object o = get(key);
byte[] value = getOptionalRaw(key); if (o instanceof byte[]) return (byte[]) o;
return value == null ? defaultValue : value; if (o instanceof Bytes) return ((Bytes) o).getBytes();
return defaultValue;
} }
public BdfList getList(String key) throws FormatException { public BdfList getList(String key) throws FormatException {
BdfList value = getOptionalList(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof BdfList) return (BdfList) o;
return value; throw new FormatException();
} }
@Nullable @Nullable
@@ -178,16 +167,16 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfList getList(String key, BdfList defaultValue) public BdfList getList(String key, BdfList defaultValue) {
throws FormatException { Object o = get(key);
BdfList value = getOptionalList(key); if (o instanceof BdfList) return (BdfList) o;
return value == null ? defaultValue : value; return defaultValue;
} }
public BdfDictionary getDictionary(String key) throws FormatException { public BdfDictionary getDictionary(String key) throws FormatException {
BdfDictionary value = getOptionalDictionary(key); Object o = get(key);
if (value == null) throw new FormatException(); if (o instanceof BdfDictionary) return (BdfDictionary) o;
return value; throw new FormatException();
} }
@Nullable @Nullable
@@ -199,9 +188,9 @@ public final class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) {
throws FormatException { Object o = get(key);
BdfDictionary value = getOptionalDictionary(key); if (o instanceof BdfDictionary) return (BdfDictionary) o;
return value == null ? defaultValue : value; return defaultValue;
} }
} }

View File

@@ -13,7 +13,7 @@ import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
@NotThreadSafe @NotThreadSafe
public final class BdfList extends ArrayList<Object> { public class BdfList extends ArrayList<Object> {
/** /**
* Factory method for constructing lists inline. * Factory method for constructing lists inline.
@@ -33,15 +33,15 @@ public final class BdfList extends ArrayList<Object> {
super(items); super(items);
} }
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isInRange(int index) { private boolean isInRange(int index) {
return index >= 0 && index < size(); return index >= 0 && index < size();
} }
public Boolean getBoolean(int index) throws FormatException { public Boolean getBoolean(int index) throws FormatException {
Boolean value = getOptionalBoolean(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof Boolean) return (Boolean) o;
throw new FormatException();
} }
@Nullable @Nullable
@@ -53,16 +53,21 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public Boolean getBoolean(int index, Boolean defaultValue) public Boolean getBoolean(int index, Boolean defaultValue) {
throws FormatException { if (!isInRange(index)) return defaultValue;
Boolean value = getOptionalBoolean(index); Object o = get(index);
return value == null ? defaultValue : value; if (o instanceof Boolean) return (Boolean) o;
return defaultValue;
} }
public Long getLong(int index) throws FormatException { public Long getLong(int index) throws FormatException {
Long value = getOptionalLong(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof Long) return (Long) o;
if (o instanceof Integer) return ((Integer) o).longValue();
if (o instanceof Short) return ((Short) o).longValue();
if (o instanceof Byte) return ((Byte) o).longValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -77,37 +82,22 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public Long getLong(int index, Long defaultValue) throws FormatException { public Long getLong(int index, Long defaultValue) {
Long value = getOptionalLong(index); if (!isInRange(index)) return defaultValue;
return value == null ? defaultValue : value; Object o = get(index);
} if (o instanceof Long) return (Long) o;
if (o instanceof Integer) return ((Integer) o).longValue();
public Integer getInt(int index) throws FormatException { if (o instanceof Short) return ((Short) o).longValue();
Integer value = getOptionalInt(index); if (o instanceof Byte) return ((Byte) o).longValue();
if (value == null) throw new FormatException(); return defaultValue;
return value;
}
@Nullable
public Integer getOptionalInt(int index) throws FormatException {
Long value = getOptionalLong(index);
if (value == null) return null;
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new FormatException();
}
return value.intValue();
}
public Integer getInt(int index, Integer defaultValue)
throws FormatException {
Integer value = getOptionalInt(index);
return value == null ? defaultValue : value;
} }
public Double getDouble(int index) throws FormatException { public Double getDouble(int index) throws FormatException {
Double value = getOptionalDouble(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof Double) return (Double) o;
if (o instanceof Float) return ((Float) o).doubleValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -120,16 +110,19 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public Double getDouble(int index, Double defaultValue) public Double getDouble(int index, Double defaultValue) {
throws FormatException { if (!isInRange(index)) return defaultValue;
Double value = getOptionalDouble(index); Object o = get(index);
return value == null ? defaultValue : value; if (o instanceof Double) return (Double) o;
if (o instanceof Float) return ((Float) o).doubleValue();
return defaultValue;
} }
public String getString(int index) throws FormatException { public String getString(int index) throws FormatException {
String value = getOptionalString(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof String) return (String) o;
throw new FormatException();
} }
@Nullable @Nullable
@@ -141,16 +134,19 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public String getString(int index, String defaultValue) public String getString(int index, String defaultValue) {
throws FormatException { if (!isInRange(index)) return defaultValue;
String value = getOptionalString(index); Object o = get(index);
return value == null ? defaultValue : value; if (o instanceof String) return (String) o;
return defaultValue;
} }
public byte[] getRaw(int index) throws FormatException { public byte[] getRaw(int index) throws FormatException {
byte[] value = getOptionalRaw(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof byte[]) return (byte[]) o;
if (o instanceof Bytes) return ((Bytes) o).getBytes();
throw new FormatException();
} }
@Nullable @Nullable
@@ -163,16 +159,19 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public byte[] getRaw(int index, byte[] defaultValue) public byte[] getRaw(int index, byte[] defaultValue) {
throws FormatException { if (!isInRange(index)) return defaultValue;
byte[] value = getOptionalRaw(index); Object o = get(index);
return value == null ? defaultValue : value; if (o instanceof byte[]) return (byte[]) o;
if (o instanceof Bytes) return ((Bytes) o).getBytes();
return defaultValue;
} }
public BdfList getList(int index) throws FormatException { public BdfList getList(int index) throws FormatException {
BdfList value = getOptionalList(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof BdfList) return (BdfList) o;
throw new FormatException();
} }
@Nullable @Nullable
@@ -184,16 +183,18 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfList getList(int index, BdfList defaultValue) public BdfList getList(int index, BdfList defaultValue) {
throws FormatException { if (!isInRange(index)) return defaultValue;
BdfList value = getOptionalList(index); Object o = get(index);
return value == null ? defaultValue : value; if (o instanceof BdfList) return (BdfList) o;
return defaultValue;
} }
public BdfDictionary getDictionary(int index) throws FormatException { public BdfDictionary getDictionary(int index) throws FormatException {
BdfDictionary value = getOptionalDictionary(index); if (!isInRange(index)) throw new FormatException();
if (value == null) throw new FormatException(); Object o = get(index);
return value; if (o instanceof BdfDictionary) return (BdfDictionary) o;
throw new FormatException();
} }
@Nullable @Nullable
@@ -206,9 +207,10 @@ public final class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) {
throws FormatException { if (!isInRange(index)) return defaultValue;
BdfDictionary value = getOptionalDictionary(index); Object o = get(index);
return value == null ? defaultValue : value; if (o instanceof BdfDictionary) return (BdfDictionary) o;
return defaultValue;
} }
} }

View File

@@ -32,12 +32,6 @@ public interface BdfReader {
void skipLong() throws IOException; void skipLong() throws IOException;
boolean hasInt() throws IOException;
int readInt() throws IOException;
void skipInt() throws IOException;
boolean hasDouble() throws IOException; boolean hasDouble() throws IOException;
double readDouble() throws IOException; double readDouble() throws IOException;
@@ -60,11 +54,23 @@ public interface BdfReader {
BdfList readList() throws IOException; BdfList readList() throws IOException;
void readListStart() throws IOException;
boolean hasListEnd() throws IOException;
void readListEnd() throws IOException;
void skipList() throws IOException; void skipList() throws IOException;
boolean hasDictionary() throws IOException; boolean hasDictionary() throws IOException;
BdfDictionary readDictionary() throws IOException; BdfDictionary readDictionary() throws IOException;
void readDictionaryStart() throws IOException;
boolean hasDictionaryEnd() throws IOException;
void readDictionaryEnd() throws IOException;
void skipDictionary() throws IOException; void skipDictionary() throws IOException;
} }

View File

@@ -9,8 +9,6 @@ public interface BdfReaderFactory {
BdfReader createReader(InputStream in); BdfReader createReader(InputStream in);
BdfReader createReader(InputStream in, boolean canonical);
BdfReader createReader(InputStream in, int nestedLimit, BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize, boolean canonical); int maxBufferSize);
} }

View File

@@ -24,5 +24,13 @@ public interface BdfWriter {
void writeList(Collection<?> c) throws IOException; void writeList(Collection<?> c) throws IOException;
void writeListStart() throws IOException;
void writeListEnd() throws IOException;
void writeDictionary(Map<?, ?> m) throws IOException; void writeDictionary(Map<?, ?> m) throws IOException;
void writeDictionaryStart() throws IOException;
void writeDictionaryEnd() throws IOException;
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.api.mailbox; package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.IoExecutor;
@@ -35,16 +34,6 @@ public interface MailboxManager {
*/ */
MailboxPairingTask startPairingTask(String qrCodePayload); MailboxPairingTask startPairingTask(String qrCodePayload);
/**
* Takes a textual QR code representation in
* {@link org.briarproject.bramble.util.Base32} format and converts it
* into a qrCodePayload as expected by {@link #startPairingTask(String)}.
*
* @throws FormatException when the provided payload did not include a
* proper briar-mailbox:// link.
*/
String convertBase32Payload(String base32Payload) throws FormatException;
/** /**
* Can be used by the UI to test the mailbox connection. * Can be used by the UI to test the mailbox connection.
* *

View File

@@ -14,7 +14,6 @@ import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.nio.charset.CodingErrorAction.IGNORE; import static java.nio.charset.CodingErrorAction.IGNORE;
import static java.nio.charset.CodingErrorAction.REPORT;
import static java.util.regex.Pattern.CASE_INSENSITIVE; import static java.util.regex.Pattern.CASE_INSENSITIVE;
@SuppressWarnings("CharsetObjectCanBeUsed") @SuppressWarnings("CharsetObjectCanBeUsed")
@@ -53,38 +52,26 @@ public class StringUtils {
return s.getBytes(UTF_8); return s.getBytes(UTF_8);
} }
public static String fromUtf8(byte[] bytes) throws FormatException { public static String fromUtf8(byte[] bytes) {
return fromUtf8(bytes, 0, bytes.length, true); return fromUtf8(bytes, 0, bytes.length);
} }
public static String fromUtf8(byte[] bytes, int off, int len) public static String fromUtf8(byte[] bytes, int off, int len) {
throws FormatException {
return fromUtf8(bytes, off, len, true);
}
private static String fromUtf8(byte[] bytes, int off, int len,
boolean strict) throws FormatException {
CharsetDecoder decoder = UTF_8.newDecoder(); CharsetDecoder decoder = UTF_8.newDecoder();
decoder.onMalformedInput(strict ? REPORT : IGNORE); decoder.onMalformedInput(IGNORE);
decoder.onUnmappableCharacter(strict ? REPORT : IGNORE); decoder.onUnmappableCharacter(IGNORE);
ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len); ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len);
try { try {
return decoder.decode(buffer).toString(); return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) { } catch (CharacterCodingException e) {
throw new FormatException(); throw new AssertionError(e);
} }
} }
public static String truncateUtf8(String s, int maxUtf8Length) { public static String truncateUtf8(String s, int maxUtf8Length) {
byte[] utf8 = toUtf8(s); byte[] utf8 = toUtf8(s);
if (utf8.length <= maxUtf8Length) return s; if (utf8.length <= maxUtf8Length) return s;
// Don't be strict when converting back, so that if we truncate a return fromUtf8(utf8, 0, maxUtf8Length);
// multi-byte character the whole character gets dropped
try {
return fromUtf8(utf8, 0, maxUtf8Length, false);
} catch (FormatException e) {
throw new AssertionError(e);
}
} }
/** /**

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.api.data; package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test; import org.junit.Test;
@@ -9,12 +8,9 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
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.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BdfDictionaryTest extends BrambleTestCase { public class BdfDictionaryTest extends BrambleTestCase {
@@ -23,20 +19,20 @@ public class BdfDictionaryTest extends BrambleTestCase {
public void testConstructors() { public void testConstructors() {
assertEquals(Collections.<String, Object>emptyMap(), assertEquals(Collections.<String, Object>emptyMap(),
new BdfDictionary()); new BdfDictionary());
assertEquals(singletonMap("foo", NULL_VALUE), assertEquals(Collections.singletonMap("foo", NULL_VALUE),
new BdfDictionary(singletonMap("foo", NULL_VALUE))); new BdfDictionary(Collections.singletonMap("foo", NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(Collections.<String, Object>emptyMap(), assertEquals(Collections.<String, Object>emptyMap(),
BdfDictionary.of()); BdfDictionary.of());
assertEquals(singletonMap("foo", NULL_VALUE), assertEquals(Collections.singletonMap("foo", NULL_VALUE),
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE))); BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
} }
@Test @Test
public void testLongPromotion() throws Exception { public void testIntegerPromotion() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("foo", (byte) 1); d.put("foo", (byte) 1);
d.put("bar", (short) 2); d.put("bar", (short) 2);
@@ -48,33 +44,6 @@ public class BdfDictionaryTest extends BrambleTestCase {
assertEquals(Long.valueOf(4), d.getLong("bam")); assertEquals(Long.valueOf(4), d.getLong("bam"));
} }
@Test
public void testIntPromotionAndDemotion() throws Exception {
BdfDictionary d = new BdfDictionary();
d.put("foo", (byte) 1);
d.put("bar", (short) 2);
d.put("baz", 3);
d.put("bam", 4L);
assertEquals(Integer.valueOf(1), d.getInt("foo"));
assertEquals(Integer.valueOf(2), d.getInt("bar"));
assertEquals(Integer.valueOf(3), d.getInt("baz"));
assertEquals(Integer.valueOf(4), d.getInt("bam"));
}
@Test(expected = FormatException.class)
public void testIntUnderflow() throws Exception {
BdfDictionary d =
BdfDictionary.of(new BdfEntry("foo", Integer.MIN_VALUE - 1L));
d.getInt("foo");
}
@Test(expected = FormatException.class)
public void testIntOverflow() throws Exception {
BdfDictionary d =
BdfDictionary.of(new BdfEntry("foo", Integer.MAX_VALUE + 1L));
d.getInt("foo");
}
@Test @Test
public void testFloatPromotion() throws Exception { public void testFloatPromotion() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
@@ -98,7 +67,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testKeySetIteratorIsOrderedByKeys() { public void testKeySetIteratorIsOrderedByKeys() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -117,7 +86,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testValuesIteratorIsOrderedByKeys() { public void testValuesIteratorIsOrderedByKeys() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -136,7 +105,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testEntrySetIteratorIsOrderedByKeys() { public void testEntrySetIteratorIsOrderedByKeys() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -161,284 +130,4 @@ public class BdfDictionaryTest extends BrambleTestCase {
assertEquals("d", e.getKey()); assertEquals("d", e.getKey());
assertEquals(4, e.getValue()); assertEquals(4, e.getValue());
} }
@Test(expected = FormatException.class)
public void testMissingValueForBooleanThrowsFormatException()
throws Exception {
new BdfDictionary().getBoolean("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForLongThrowsFormatException()
throws Exception {
new BdfDictionary().getLong("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForIntThrowsFormatException() throws Exception {
new BdfDictionary().getInt("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForDoubleThrowsFormatException()
throws Exception {
new BdfDictionary().getDouble("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForStringThrowsFormatException()
throws Exception {
new BdfDictionary().getString("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForRawThrowsFormatException() throws Exception {
new BdfDictionary().getRaw("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForListThrowsFormatException()
throws Exception {
new BdfDictionary().getList("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForDictionaryThrowsFormatException()
throws Exception {
new BdfDictionary().getDictionary("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getBoolean("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForLongThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getLong("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForIntThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getInt("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForDoubleThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getDouble("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForStringThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getString("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForRawThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getRaw("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForListThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getList("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getDictionary("foo");
}
@Test
public void testOptionalMethodsReturnNullForMissingValue()
throws Exception {
testOptionalMethodsReturnNull(new BdfDictionary());
}
@Test
public void testOptionalMethodsReturnNullForNullValue() throws Exception {
BdfDictionary d = BdfDictionary.of(new BdfEntry("foo", NULL_VALUE));
testOptionalMethodsReturnNull(d);
}
private void testOptionalMethodsReturnNull(BdfDictionary d)
throws Exception {
assertNull(d.getOptionalBoolean("foo"));
assertNull(d.getOptionalLong("foo"));
assertNull(d.getOptionalInt("foo"));
assertNull(d.getOptionalDouble("foo"));
assertNull(d.getOptionalString("foo"));
assertNull(d.getOptionalRaw("foo"));
assertNull(d.getOptionalList("foo"));
assertNull(d.getOptionalDictionary("foo"));
}
@Test
public void testDefaultMethodsReturnDefaultForMissingValue()
throws Exception {
testDefaultMethodsReturnDefault(new BdfDictionary());
}
@Test
public void testDefaultMethodsReturnDefaultForNullValue() throws Exception {
BdfDictionary d = BdfDictionary.of(new BdfEntry("foo", NULL_VALUE));
testDefaultMethodsReturnDefault(d);
}
private void testDefaultMethodsReturnDefault(BdfDictionary d)
throws Exception {
assertEquals(TRUE, d.getBoolean("foo", TRUE));
assertEquals(Long.valueOf(123L), d.getLong("foo", 123L));
assertEquals(Integer.valueOf(123), d.getInt("foo", 123));
assertEquals(Double.valueOf(123D), d.getDouble("foo", 123D));
assertEquals("123", d.getString("foo", "123"));
byte[] defaultRaw = {1, 2, 3};
assertArrayEquals(defaultRaw, d.getRaw("foo", defaultRaw));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, d.getList("foo", defaultList));
BdfDictionary defaultDict = BdfDictionary.of(new BdfEntry("123", 123));
assertEquals(defaultDict, d.getDictionary("foo", defaultDict));
}
@Test(expected = FormatException.class)
public void testWrongTypeForBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getBoolean("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalBoolean("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getBoolean("foo", true);
}
@Test(expected = FormatException.class)
public void testWrongTypeForLongThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getLong("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalLongThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getOptionalLong("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultLongThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getLong("foo", 1L);
}
@Test(expected = FormatException.class)
public void testWrongTypeForIntThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getInt("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalIntThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getOptionalInt("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultIntThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getInt("foo", 1);
}
@Test(expected = FormatException.class)
public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDouble("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalDoubleThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalDouble("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDoubleThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDouble("foo", 1D);
}
@Test(expected = FormatException.class)
public void testWrongTypeForStringThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getString("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalStringThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalString("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultStringThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getString("foo", "");
}
@Test(expected = FormatException.class)
public void testWrongTypeForRawThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getRaw("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalRawThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalRaw("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultRawThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getRaw("foo", new byte[0]);
}
@Test(expected = FormatException.class)
public void testWrongTypeForListThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getList("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalListThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalList("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultListThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getList("foo",
new BdfList());
}
@Test(expected = FormatException.class)
public void testWrongTypeForDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDictionary("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalDictionary("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDictionary("foo",
new BdfDictionary());
}
} }

View File

@@ -5,31 +5,31 @@ import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test; import org.junit.Test;
import static java.lang.Boolean.TRUE; import java.util.Arrays;
import static java.util.Arrays.asList; import java.util.Collections;
import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
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.assertNull;
public class BdfListTest extends BrambleTestCase { public class BdfListTest extends BrambleTestCase {
@Test @Test
public void testConstructors() { public void testConstructors() {
assertEquals(emptyList(), new BdfList()); assertEquals(Collections.emptyList(), new BdfList());
assertEquals(asList(1, 2, NULL_VALUE), assertEquals(Arrays.asList(1, 2, NULL_VALUE),
new BdfList(asList(1, 2, NULL_VALUE))); new BdfList(Arrays.asList(1, 2, NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(emptyList(), BdfList.of()); assertEquals(Collections.emptyList(), BdfList.of());
assertEquals(asList(1, 2, NULL_VALUE), BdfList.of(1, 2, NULL_VALUE)); assertEquals(Arrays.asList(1, 2, NULL_VALUE),
BdfList.of(1, 2, NULL_VALUE));
} }
@Test @Test
public void testLongPromotion() throws Exception { public void testIntegerPromotion() throws Exception {
BdfList list = new BdfList(); BdfList list = new BdfList();
list.add((byte) 1); list.add((byte) 1);
list.add((short) 2); list.add((short) 2);
@@ -41,31 +41,6 @@ public class BdfListTest extends BrambleTestCase {
assertEquals(Long.valueOf(4), list.getLong(3)); assertEquals(Long.valueOf(4), list.getLong(3));
} }
@Test
public void testIntPromotionAndDemotion() throws Exception {
BdfList list = new BdfList();
list.add((byte) 1);
list.add((short) 2);
list.add(3);
list.add(4L);
assertEquals(Integer.valueOf(1), list.getInt(0));
assertEquals(Integer.valueOf(2), list.getInt(1));
assertEquals(Integer.valueOf(3), list.getInt(2));
assertEquals(Integer.valueOf(4), list.getInt(3));
}
@Test(expected = FormatException.class)
public void testIntUnderflow() throws Exception {
BdfList list = BdfList.of(Integer.MIN_VALUE - 1L);
list.getInt(0);
}
@Test(expected = FormatException.class)
public void testIntOverflow() throws Exception {
BdfList list = BdfList.of(Integer.MAX_VALUE + 1L);
list.getInt(0);
}
@Test @Test
public void testFloatPromotion() throws Exception { public void testFloatPromotion() throws Exception {
BdfList list = new BdfList(); BdfList list = new BdfList();
@@ -88,6 +63,61 @@ public class BdfListTest extends BrambleTestCase {
assertArrayEquals(new byte[123], second); assertArrayEquals(new byte[123], second);
} }
@Test
@SuppressWarnings("ConstantConditions")
public void testIndexOutOfBoundsReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3);
boolean defaultBoolean = true;
assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean));
assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean));
Long defaultLong = 123L;
assertEquals(defaultLong, list.getLong(-1, defaultLong));
assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = 1.23;
assertEquals(defaultDouble, list.getDouble(-1, defaultDouble));
assertEquals(defaultDouble, list.getDouble(3, defaultDouble));
String defaultString = "123";
assertEquals(defaultString, list.getString(-1, defaultString));
assertEquals(defaultString, list.getString(3, defaultString));
byte[] defaultBytes = new byte[] {1, 2, 3};
assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes));
assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(-1, defaultList));
assertEquals(defaultList, list.getList(3, defaultList));
BdfDictionary defaultDict = BdfDictionary.of(
new BdfEntry("1", 1),
new BdfEntry("2", 2),
new BdfEntry("3", 3)
);
assertEquals(defaultDict, list.getDictionary(-1, defaultDict));
assertEquals(defaultDict, list.getDictionary(3, defaultDict));
}
@Test
@SuppressWarnings("ConstantConditions")
public void testWrongTypeReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3, true);
boolean defaultBoolean = true;
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
Long defaultLong = 123L;
assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = 1.23;
assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
String defaultString = "123";
assertEquals(defaultString, list.getString(0, defaultString));
byte[] defaultBytes = new byte[] {1, 2, 3};
assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(0, defaultList));
BdfDictionary defaultDict = BdfDictionary.of(
new BdfEntry("1", 1),
new BdfEntry("2", 2),
new BdfEntry("3", 3)
);
assertEquals(defaultDict, list.getDictionary(0, defaultDict));
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForBooleanThrowsFormatException() public void testNegativeIndexForBooleanThrowsFormatException()
throws Exception { throws Exception {
@@ -100,12 +130,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalBoolean(-1); new BdfList().getOptionalBoolean(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultBooleanThrowsFormatException()
throws Exception {
new BdfList().getBoolean(-1, true);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForLongThrowsFormatException() public void testNegativeIndexForLongThrowsFormatException()
throws Exception { throws Exception {
@@ -118,30 +142,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalLong(-1); new BdfList().getOptionalLong(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultLongThrowsFormatException()
throws Exception {
new BdfList().getLong(-1, 1L);
}
@Test(expected = FormatException.class)
public void testNegativeIndexForIntThrowsFormatException()
throws Exception {
new BdfList().getInt(-1);
}
@Test(expected = FormatException.class)
public void testNegativeIndexForOptionalIntThrowsFormatException()
throws Exception {
new BdfList().getOptionalInt(-1);
}
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultIntThrowsFormatException()
throws Exception {
new BdfList().getInt(-1, 1);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForDoubleThrowsFormatException() public void testNegativeIndexForDoubleThrowsFormatException()
throws Exception { throws Exception {
@@ -154,12 +154,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalDouble(-1); new BdfList().getOptionalDouble(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultDoubleThrowsFormatException()
throws Exception {
new BdfList().getDouble(-1, 1D);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForStringThrowsFormatException() public void testNegativeIndexForStringThrowsFormatException()
throws Exception { throws Exception {
@@ -172,12 +166,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalString(-1); new BdfList().getOptionalString(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultStringThrowsFormatException()
throws Exception {
new BdfList().getString(-1, "");
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForRawThrowsFormatException() public void testNegativeIndexForRawThrowsFormatException()
throws Exception { throws Exception {
@@ -190,12 +178,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalRaw(-1); new BdfList().getOptionalRaw(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultRawThrowsFormatException()
throws Exception {
new BdfList().getRaw(-1, new byte[0]);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForListThrowsFormatException() public void testNegativeIndexForListThrowsFormatException()
throws Exception { throws Exception {
@@ -208,11 +190,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalList(-1); new BdfList().getOptionalList(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultListThrowsFormatException()
throws Exception {
new BdfList().getList(-1, new BdfList());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForDictionaryThrowsFormatException() public void testNegativeIndexForDictionaryThrowsFormatException()
@@ -226,12 +203,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalDictionary(-1); new BdfList().getOptionalDictionary(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultDictionaryThrowsFormatException()
throws Exception {
new BdfList().getDictionary(-1, new BdfDictionary());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForBooleanThrowsFormatException() public void testTooLargeIndexForBooleanThrowsFormatException()
throws Exception { throws Exception {
@@ -244,12 +215,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalBoolean(0); new BdfList().getOptionalBoolean(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultBooleanThrowsFormatException()
throws Exception {
new BdfList().getBoolean(0, true);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForLongThrowsFormatException() public void testTooLargeIndexForLongThrowsFormatException()
throws Exception { throws Exception {
@@ -262,30 +227,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalLong(0); new BdfList().getOptionalLong(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultLongThrowsFormatException()
throws Exception {
new BdfList().getLong(0, 1L);
}
@Test(expected = FormatException.class)
public void testTooLargeIndexForIntThrowsFormatException()
throws Exception {
new BdfList().getInt(0);
}
@Test(expected = FormatException.class)
public void testTooLargeIndexForOptionalIntThrowsFormatException()
throws Exception {
new BdfList().getOptionalInt(0);
}
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultIntThrowsFormatException()
throws Exception {
new BdfList().getInt(0, 1);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForDoubleThrowsFormatException() public void testTooLargeIndexForDoubleThrowsFormatException()
throws Exception { throws Exception {
@@ -298,12 +239,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalDouble(0); new BdfList().getOptionalDouble(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultDoubleThrowsFormatException()
throws Exception {
new BdfList().getDouble(0, 1D);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForStringThrowsFormatException() public void testTooLargeIndexForStringThrowsFormatException()
throws Exception { throws Exception {
@@ -316,12 +251,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalString(0); new BdfList().getOptionalString(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultStringThrowsFormatException()
throws Exception {
new BdfList().getString(0, "");
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForRawThrowsFormatException() public void testTooLargeIndexForRawThrowsFormatException()
throws Exception { throws Exception {
@@ -334,12 +263,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalRaw(0); new BdfList().getOptionalRaw(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultRawThrowsFormatException()
throws Exception {
new BdfList().getRaw(0, new byte[0]);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForListThrowsFormatException() public void testTooLargeIndexForListThrowsFormatException()
throws Exception { throws Exception {
@@ -352,11 +275,6 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalList(0); new BdfList().getOptionalList(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultListThrowsFormatException()
throws Exception {
new BdfList().getList(0, new BdfList());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForDictionaryThrowsFormatException() public void testTooLargeIndexForDictionaryThrowsFormatException()
@@ -369,13 +287,6 @@ public class BdfListTest extends BrambleTestCase {
throws Exception { throws Exception {
new BdfList().getOptionalDictionary(0); new BdfList().getOptionalDictionary(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultDictionaryThrowsFormatException()
throws Exception {
new BdfList().getDictionary(0, new BdfDictionary());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForBooleanThrowsFormatException() public void testWrongTypeForBooleanThrowsFormatException()
throws Exception { throws Exception {
@@ -388,12 +299,6 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalBoolean(0); BdfList.of(123).getOptionalBoolean(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultBooleanThrowsFormatException()
throws Exception {
BdfList.of(123).getBoolean(0, true);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForLongThrowsFormatException() throws Exception { public void testWrongTypeForLongThrowsFormatException() throws Exception {
BdfList.of(1.23).getLong(0); BdfList.of(1.23).getLong(0);
@@ -405,29 +310,6 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(1.23).getOptionalLong(0); BdfList.of(1.23).getOptionalLong(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultLongThrowsFormatException()
throws Exception {
BdfList.of(1.23).getLong(0, 1L);
}
@Test(expected = FormatException.class)
public void testWrongTypeForIntThrowsFormatException() throws Exception {
BdfList.of(1.23).getInt(0);
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalIntThrowsFormatException()
throws Exception {
BdfList.of(1.23).getOptionalInt(0);
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultIntThrowsFormatException()
throws Exception {
BdfList.of(1.23).getInt(0, 1);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForDoubleThrowsFormatException() throws Exception { public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
BdfList.of(123).getDouble(0); BdfList.of(123).getDouble(0);
@@ -439,12 +321,6 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalDouble(0); BdfList.of(123).getOptionalDouble(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDoubleThrowsFormatException()
throws Exception {
BdfList.of(123).getDouble(0, 1D);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForStringThrowsFormatException() throws Exception { public void testWrongTypeForStringThrowsFormatException() throws Exception {
BdfList.of(123).getString(0); BdfList.of(123).getString(0);
@@ -456,12 +332,6 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalString(0); BdfList.of(123).getOptionalString(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultStringThrowsFormatException()
throws Exception {
BdfList.of(123).getString(0, "");
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForRawThrowsFormatException() throws Exception { public void testWrongTypeForRawThrowsFormatException() throws Exception {
BdfList.of(123).getRaw(0); BdfList.of(123).getRaw(0);
@@ -473,12 +343,6 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalRaw(0); BdfList.of(123).getOptionalRaw(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultRawThrowsFormatException()
throws Exception {
BdfList.of(123).getRaw(0, new byte[0]);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForListThrowsFormatException() throws Exception { public void testWrongTypeForListThrowsFormatException() throws Exception {
BdfList.of(123).getList(0); BdfList.of(123).getList(0);
@@ -490,11 +354,6 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalList(0); BdfList.of(123).getOptionalList(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultListThrowsFormatException()
throws Exception {
BdfList.of(123).getList(0, new BdfList());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForDictionaryThrowsFormatException() public void testWrongTypeForDictionaryThrowsFormatException()
@@ -507,81 +366,4 @@ public class BdfListTest extends BrambleTestCase {
throws Exception { throws Exception {
BdfList.of(123).getOptionalDictionary(0); BdfList.of(123).getOptionalDictionary(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDictionaryThrowsFormatException()
throws Exception {
BdfList.of(123).getDictionary(0, new BdfDictionary());
}
@Test(expected = FormatException.class)
public void testNullValueForBooleanThrowsFormatException()
throws Exception {
BdfList.of(NULL_VALUE).getBoolean(0);
}
@Test(expected = FormatException.class)
public void testNullValueForLongThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getLong(0);
}
@Test(expected = FormatException.class)
public void testNullValueForIntThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getInt(0);
}
@Test(expected = FormatException.class)
public void testNullValueForDoubleThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getDouble(0);
}
@Test(expected = FormatException.class)
public void testNullValueForStringThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getString(0);
}
@Test(expected = FormatException.class)
public void testNullValueForRawThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getRaw(0);
}
@Test(expected = FormatException.class)
public void testNullValueForListThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getList(0);
}
@Test(expected = FormatException.class)
public void testNullValueForDictionaryThrowsFormatException()
throws Exception {
BdfList.of(NULL_VALUE).getDictionary(0);
}
@Test
public void testOptionalMethodsReturnNullForNullValue() throws Exception {
BdfList list = BdfList.of(NULL_VALUE);
assertNull(list.getOptionalBoolean(0));
assertNull(list.getOptionalLong(0));
assertNull(list.getOptionalInt(0));
assertNull(list.getOptionalDouble(0));
assertNull(list.getOptionalString(0));
assertNull(list.getOptionalRaw(0));
assertNull(list.getOptionalList(0));
assertNull(list.getOptionalDictionary(0));
}
@Test
public void testDefaultMethodsReturnDefaultForNullValue() throws Exception {
BdfList list = BdfList.of(NULL_VALUE);
assertEquals(TRUE, list.getBoolean(0, TRUE));
assertEquals(Long.valueOf(123L), list.getLong(0, 123L));
assertEquals(Integer.valueOf(123), list.getInt(0, 123));
assertEquals(Double.valueOf(123D), list.getDouble(0, 123D));
assertEquals("123", list.getString(0, "123"));
byte[] defaultRaw = {1, 2, 3};
assertArrayEquals(defaultRaw, list.getRaw(0, defaultRaw));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(0, defaultList));
BdfDictionary defaultDict = BdfDictionary.of(new BdfEntry("123", 123));
assertEquals(defaultDict, list.getDictionary(0, defaultDict));
}
} }

View File

@@ -155,13 +155,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList getMessageAsList(Transaction txn, MessageId m) public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
return getMessageAsList(txn, m, true); return toList(db.getMessage(txn, m).getBody());
}
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m,
boolean canonical) throws DbException, FormatException {
return toList(db.getMessage(txn, m), canonical);
} }
@Override @Override
@@ -319,13 +313,8 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList toList(byte[] b, int off, int len) throws FormatException { public BdfList toList(byte[] b, int off, int len) throws FormatException {
return toList(b, off, len, true);
}
private BdfList toList(byte[] b, int off, int len, boolean canonical)
throws FormatException {
ByteArrayInputStream in = new ByteArrayInputStream(b, off, len); ByteArrayInputStream in = new ByteArrayInputStream(b, off, len);
BdfReader reader = bdfReaderFactory.createReader(in, canonical); BdfReader reader = bdfReaderFactory.createReader(in);
try { try {
BdfList list = reader.readList(); BdfList list = reader.readList();
if (!reader.eof()) throw new FormatException(); if (!reader.eof()) throw new FormatException();
@@ -339,7 +328,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList toList(byte[] b) throws FormatException { public BdfList toList(byte[] b) throws FormatException {
return toList(b, 0, b.length, true); return toList(b, 0, b.length);
} }
@Override @Override
@@ -347,12 +336,6 @@ class ClientHelperImpl implements ClientHelper {
return toList(m.getBody()); return toList(m.getBody());
} }
@Override
public BdfList toList(Message m, boolean canonical) throws FormatException {
byte[] b = m.getBody();
return toList(b, 0, b.length, canonical);
}
@Override @Override
public BdfList toList(Author a) { public BdfList toList(Author a) {
return BdfList.of(a.getFormatVersion(), a.getName(), a.getPublicKey()); return BdfList.of(a.getFormatVersion(), a.getName(), a.getPublicKey());
@@ -378,7 +361,7 @@ class ClientHelperImpl implements ClientHelper {
public Author parseAndValidateAuthor(BdfList author) public Author parseAndValidateAuthor(BdfList author)
throws FormatException { throws FormatException {
checkSize(author, 3); checkSize(author, 3);
int formatVersion = author.getInt(0); int formatVersion = author.getLong(0).intValue();
if (formatVersion != FORMAT_VERSION) throw new FormatException(); if (formatVersion != FORMAT_VERSION) throw new FormatException();
String name = author.getString(1); String name = author.getString(1);
checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
@@ -489,7 +472,8 @@ class ClientHelperImpl implements ClientHelper {
if (element.size() != 2) { if (element.size() != 2) {
throw new FormatException(); throw new FormatException();
} }
list.add(new MailboxVersion(element.getInt(0), element.getInt(1))); list.add(new MailboxVersion(element.getLong(0).intValue(),
element.getLong(1).intValue()));
} }
// Sort the list of versions for easier comparison // Sort the list of versions for easier comparison
sort(list); sort(list);
@@ -502,7 +486,7 @@ class ClientHelperImpl implements ClientHelper {
try { try {
BdfDictionary meta = BdfDictionary meta =
getGroupMetadataAsDictionary(txn, contactGroupId); getGroupMetadataAsDictionary(txn, contactGroupId);
return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID)); return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); // Invalid group metadata throw new DbException(e); // Invalid group metadata
} }

View File

@@ -18,18 +18,12 @@ 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, true); DEFAULT_MAX_BUFFER_SIZE);
}
@Override
public BdfReader createReader(InputStream in, boolean canonical) {
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, canonical);
} }
@Override @Override
public BdfReader createReader(InputStream in, int nestedLimit, public BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize, boolean canonical) { int maxBufferSize) {
return new BdfReaderImpl(in, nestedLimit, maxBufferSize, canonical); return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
} }
} }

View File

@@ -33,24 +33,21 @@ import static org.briarproject.bramble.util.StringUtils.fromUtf8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
final class BdfReaderImpl implements BdfReader { 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, maxBufferSize; private final int nestedLimit, maxBufferSize;
private final boolean canonical;
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, int maxBufferSize, BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) {
boolean canonical) {
this.in = in; this.in = in;
this.nestedLimit = nestedLimit; this.nestedLimit = nestedLimit;
this.maxBufferSize = maxBufferSize; this.maxBufferSize = maxBufferSize;
this.canonical = canonical;
} }
private void readLookahead() throws IOException { private void readLookahead() throws IOException {
@@ -191,22 +188,13 @@ final class BdfReaderImpl implements BdfReader {
private short readInt16() throws IOException { private short readInt16() throws IOException {
readIntoBuffer(2); readIntoBuffer(2);
short value = (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF)); return (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF));
if (canonical && value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
// Value could have been encoded as an INT_8
throw new FormatException();
}
return value;
} }
private int readInt32() throws IOException { private int readInt32() throws IOException {
readIntoBuffer(4); readIntoBuffer(4);
int value = 0; int value = 0;
for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8); for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
if (canonical && value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
// Value could have been encoded as an INT_16
throw new FormatException();
}
return value; return value;
} }
@@ -214,11 +202,6 @@ final class BdfReaderImpl implements BdfReader {
readIntoBuffer(8); readIntoBuffer(8);
long value = 0; long value = 0;
for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8); for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
if (canonical && value >= Integer.MIN_VALUE &&
value <= Integer.MAX_VALUE) {
// Value could have been encoded as an INT_32
throw new FormatException();
}
return value; return value;
} }
@@ -232,31 +215,6 @@ final class BdfReaderImpl implements BdfReader {
hasLookahead = false; hasLookahead = false;
} }
@Override
public boolean hasInt() throws IOException {
if (!hasLookahead) readLookahead();
if (eof) return false;
return next == INT_8 || next == INT_16 || next == INT_32;
}
@Override
public int readInt() throws IOException {
if (!hasInt()) throw new FormatException();
hasLookahead = false;
if (next == INT_8) return readInt8();
if (next == INT_16) return readInt16();
return readInt32();
}
@Override
public void skipInt() throws IOException {
if (!hasInt()) throw new FormatException();
if (next == INT_8) skip(1);
else if (next == INT_16) skip(2);
else skip(4);
hasLookahead = false;
}
@Override @Override
public boolean hasDouble() throws IOException { public boolean hasDouble() throws IOException {
if (!hasLookahead) readLookahead(); if (!hasLookahead) readLookahead();
@@ -365,19 +323,35 @@ final class BdfReaderImpl implements BdfReader {
private BdfList readList(int level) throws IOException { private BdfList readList(int level) throws IOException {
if (!hasList()) throw new FormatException(); if (!hasList()) throw new FormatException();
if (level > nestedLimit) throw new FormatException(); if (level > nestedLimit) throw new FormatException();
hasLookahead = false;
BdfList list = new BdfList(); BdfList list = new BdfList();
while (!hasEnd()) list.add(readObject(level + 1)); readListStart();
readEnd(); while (!hasListEnd()) list.add(readObject(level + 1));
readListEnd();
return list; return list;
} }
@Override
public void readListStart() throws IOException {
if (!hasList()) throw new FormatException();
hasLookahead = false;
}
@Override
public boolean hasListEnd() throws IOException {
return hasEnd();
}
private boolean hasEnd() throws IOException { private boolean hasEnd() throws IOException {
if (!hasLookahead) readLookahead(); if (!hasLookahead) readLookahead();
if (eof) return false; if (eof) return false;
return next == END; return next == END;
} }
@Override
public void readListEnd() throws IOException {
readEnd();
}
private void readEnd() throws IOException { private void readEnd() throws IOException {
if (!hasEnd()) throw new FormatException(); if (!hasEnd()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
@@ -387,7 +361,7 @@ final class BdfReaderImpl implements BdfReader {
public void skipList() throws IOException { public void skipList() throws IOException {
if (!hasList()) throw new FormatException(); if (!hasList()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
while (!hasEnd()) skipObject(); while (!hasListEnd()) skipObject();
hasLookahead = false; hasLookahead = false;
} }
@@ -406,27 +380,35 @@ final class BdfReaderImpl implements BdfReader {
private BdfDictionary readDictionary(int level) throws IOException { private BdfDictionary readDictionary(int level) throws IOException {
if (!hasDictionary()) throw new FormatException(); if (!hasDictionary()) throw new FormatException();
if (level > nestedLimit) throw new FormatException(); if (level > nestedLimit) throw new FormatException();
hasLookahead = false;
BdfDictionary dictionary = new BdfDictionary(); BdfDictionary dictionary = new BdfDictionary();
String prevKey = null; readDictionaryStart();
while (!hasEnd()) { while (!hasDictionaryEnd())
String key = readString(); dictionary.put(readString(), readObject(level + 1));
if (canonical && prevKey != null && key.compareTo(prevKey) <= 0) { readDictionaryEnd();
// Keys not unique and sorted
throw new FormatException();
}
dictionary.put(key, readObject(level + 1));
prevKey = key;
}
readEnd();
return dictionary; return dictionary;
} }
@Override
public void readDictionaryStart() throws IOException {
if (!hasDictionary()) throw new FormatException();
hasLookahead = false;
}
@Override
public boolean hasDictionaryEnd() throws IOException {
return hasEnd();
}
@Override
public void readDictionaryEnd() throws IOException {
readEnd();
}
@Override @Override
public void skipDictionary() throws IOException { public void skipDictionary() throws IOException {
if (!hasDictionary()) throw new FormatException(); if (!hasDictionary()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
while (!hasEnd()) { while (!hasDictionaryEnd()) {
skipString(); skipString();
skipObject(); skipObject();
} }

View File

@@ -2,13 +2,11 @@ package org.briarproject.bramble.data;
import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfWriter; import org.briarproject.bramble.api.data.BdfWriter;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -17,7 +15,6 @@ import java.util.Map.Entry;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.util.Collections.sort;
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.data.Types.DICTIONARY; import static org.briarproject.bramble.data.Types.DICTIONARY;
import static org.briarproject.bramble.data.Types.END; import static org.briarproject.bramble.data.Types.END;
@@ -36,11 +33,10 @@ import static org.briarproject.bramble.data.Types.STRING_16;
import static org.briarproject.bramble.data.Types.STRING_32; import static org.briarproject.bramble.data.Types.STRING_32;
import static org.briarproject.bramble.data.Types.STRING_8; import static org.briarproject.bramble.data.Types.STRING_8;
import static org.briarproject.bramble.data.Types.TRUE; import static org.briarproject.bramble.data.Types.TRUE;
import static org.briarproject.bramble.util.StringUtils.UTF_8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
final class BdfWriterImpl implements BdfWriter { class BdfWriterImpl implements BdfWriter {
private final OutputStream out; private final OutputStream out;
@@ -117,7 +113,7 @@ final class BdfWriterImpl implements BdfWriter {
@Override @Override
public void writeString(String s) throws IOException { public void writeString(String s) throws IOException {
byte[] b = s.getBytes(UTF_8); byte[] b = s.getBytes("UTF-8");
if (b.length <= Byte.MAX_VALUE) { if (b.length <= Byte.MAX_VALUE) {
out.write(STRING_8); out.write(STRING_8);
out.write((byte) b.length); out.write((byte) b.length);
@@ -165,33 +161,39 @@ final class BdfWriterImpl implements BdfWriter {
else if (o instanceof String) writeString((String) o); else if (o instanceof String) writeString((String) o);
else if (o instanceof byte[]) writeRaw((byte[]) o); else if (o instanceof byte[]) writeRaw((byte[]) o);
else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes()); else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes());
else if (o instanceof List) writeList((List<?>) o); else if (o instanceof List) writeList((List) o);
else if (o instanceof Map) writeDictionary((Map<?, ?>) o); else if (o instanceof Map) writeDictionary((Map) o);
else throw new FormatException(); else throw new FormatException();
} }
@Override
public void writeListStart() throws IOException {
out.write(LIST);
}
@Override
public void writeListEnd() throws IOException {
out.write(END);
}
@Override @Override
public void writeDictionary(Map<?, ?> m) throws IOException { public void writeDictionary(Map<?, ?> m) throws IOException {
out.write(DICTIONARY); out.write(DICTIONARY);
if (m instanceof BdfDictionary) { for (Entry<?, ?> e : m.entrySet()) {
// Entries are already sorted and keys are known to be strings if (!(e.getKey() instanceof String)) throw new FormatException();
for (Entry<String, Object> e : ((BdfDictionary) m).entrySet()) { writeString((String) e.getKey());
writeString(e.getKey()); writeObject(e.getValue());
writeObject(e.getValue());
}
} else {
// Check that keys are strings, write entries in canonical order
List<String> keys = new ArrayList<>(m.size());
for (Object k : m.keySet()) {
if (!(k instanceof String)) throw new FormatException();
keys.add((String) k);
}
sort(keys);
for (String key : keys) {
writeString(key);
writeObject(m.get(key));
}
} }
out.write(END); out.write(END);
} }
@Override
public void writeDictionaryStart() throws IOException {
out.write(DICTIONARY);
}
@Override
public void writeDictionaryEnd() throws IOException {
out.write(END);
}
} }

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.keyagreement; package org.briarproject.bramble.keyagreement;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.BdfWriter; import org.briarproject.bramble.api.data.BdfWriter;
import org.briarproject.bramble.api.data.BdfWriterFactory; import org.briarproject.bramble.api.data.BdfWriterFactory;
import org.briarproject.bramble.api.keyagreement.Payload; import org.briarproject.bramble.api.keyagreement.Payload;
@@ -33,14 +32,13 @@ class PayloadEncoderImpl implements PayloadEncoder {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
int formatIdAndVersion = (QR_FORMAT_ID << 5) | QR_FORMAT_VERSION; int formatIdAndVersion = (QR_FORMAT_ID << 5) | QR_FORMAT_VERSION;
out.write(formatIdAndVersion); out.write(formatIdAndVersion);
BdfList payload = new BdfList();
payload.add(p.getCommitment());
for (TransportDescriptor d : p.getTransportDescriptors()) {
payload.add(d.getDescriptor());
}
BdfWriter w = bdfWriterFactory.createWriter(out); BdfWriter w = bdfWriterFactory.createWriter(out);
try { try {
w.writeList(payload); w.writeListStart(); // Payload start
w.writeRaw(p.getCommitment());
for (TransportDescriptor d : p.getTransportDescriptors())
w.writeList(d.getDescriptor());
w.writeListEnd(); // Payload end
} catch (IOException e) { } catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream // Shouldn't happen with ByteArrayOutputStream
throw new AssertionError(e); throw new AssertionError(e);

View File

@@ -73,7 +73,7 @@ class PayloadParserImpl implements PayloadParser {
List<TransportDescriptor> recognised = new ArrayList<>(); List<TransportDescriptor> recognised = new ArrayList<>();
for (int i = 1; i < payload.size(); i++) { for (int i = 1; i < payload.size(); i++) {
BdfList descriptor = payload.getList(i); BdfList descriptor = payload.getList(i);
int transportId = descriptor.getInt(0); long transportId = descriptor.getLong(0);
if (transportId == TRANSPORT_ID_BLUETOOTH) { if (transportId == TRANSPORT_ID_BLUETOOTH) {
TransportId id = BluetoothConstants.ID; TransportId id = BluetoothConstants.ID;
recognised.add(new TransportDescriptor(id, descriptor)); recognised.add(new TransportDescriptor(id, descriptor));

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.mailbox; package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
@@ -12,15 +11,12 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxStatus; import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.Base32;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
@@ -30,7 +26,6 @@ import javax.inject.Inject;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
@@ -103,22 +98,6 @@ class MailboxManagerImpl implements MailboxManager {
return created; return created;
} }
@Override
public String convertBase32Payload(String base32Payload)
throws FormatException {
Pattern regex = Pattern.compile("(briar-mailbox://)?([a-z2-7]{104})");
Matcher matcher = regex.matcher(base32Payload);
if (!matcher.find()) throw new FormatException();
String base32 = matcher.group(2);
byte[] payloadBytes;
try {
payloadBytes = Base32.decode(base32, false);
} catch (IllegalArgumentException e) {
throw new FormatException();
}
return new String(payloadBytes, ISO_8859_1);
}
@Override @Override
public boolean checkConnection() { public boolean checkConnection() {
List<MailboxVersion> versions = null; List<MailboxVersion> versions = null;

View File

@@ -419,7 +419,7 @@ class LanTcpPlugin extends TcpPlugin {
private InetSocketAddress parseSocketAddress(BdfList descriptor) private InetSocketAddress parseSocketAddress(BdfList descriptor)
throws FormatException { throws FormatException {
byte[] address = descriptor.getRaw(1); byte[] address = descriptor.getRaw(1);
int port = descriptor.getInt(2); int port = descriptor.getLong(2).intValue();
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException(); if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
try { try {
InetAddress addr = InetAddress.getByAddress(address); InetAddress addr = InetAddress.getByAddress(address);

View File

@@ -201,7 +201,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) { for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
e.getValue().messageId, false); e.getValue().messageId);
local.put(e.getKey(), parseProperties(message)); local.put(e.getKey(), parseProperties(message));
} }
return local; return local;
@@ -222,7 +222,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
if (latest != null) { if (latest != null) {
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId, false); latest.messageId);
p = parseProperties(message); p = parseProperties(message);
} }
return p == null ? new TransportProperties() : p; return p == null ? new TransportProperties() : p;
@@ -252,7 +252,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
local = new TransportProperties(); local = new TransportProperties();
} else { } else {
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId, false); latest.messageId);
local = parseProperties(message); local = parseProperties(message);
} }
storeLocalProperties(txn, c, t, local); storeLocalProperties(txn, c, t, local);
@@ -272,8 +272,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
remote = new TransportProperties(); remote = new TransportProperties();
} else { } else {
// Retrieve and parse the latest remote properties // Retrieve and parse the latest remote properties
BdfList message = clientHelper.getMessageAsList(txn, BdfList message =
latest.messageId, false); clientHelper.getMessageAsList(txn, latest.messageId);
remote = parseProperties(message); remote = parseProperties(message);
} }
// Merge in any discovered properties // Merge in any discovered properties
@@ -317,7 +317,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
changed = true; changed = true;
} else { } else {
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId, false); latest.messageId);
TransportProperties old = parseProperties(message); TransportProperties old = parseProperties(message);
merged = new TransportProperties(old); merged = new TransportProperties(old);
for (Entry<String, String> e : p.entrySet()) { for (Entry<String, String> e : p.entrySet()) {

View File

@@ -27,10 +27,7 @@ class TransportPropertyValidator extends BdfMessageValidator {
TransportPropertyValidator(ClientHelper clientHelper, TransportPropertyValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) { MetadataEncoder metadataEncoder, Clock clock) {
// Accept transport properties in non-canonical form super(clientHelper, metadataEncoder, clock);
// TODO: Remove this after a reasonable migration period
// (added 2023-02-17)
super(clientHelper, metadataEncoder, clock, false);
} }
@Override @Override

View File

@@ -30,7 +30,6 @@ import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY; import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS; import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES; import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
@@ -127,8 +126,6 @@ class SyncRecordReaderImpl implements SyncRecordReader {
byte[] payload = nextRecord.getPayload(); byte[] payload = nextRecord.getPayload();
if (payload.length <= MESSAGE_HEADER_LENGTH) if (payload.length <= MESSAGE_HEADER_LENGTH)
throw new FormatException(); throw new FormatException();
if (payload.length > MAX_MESSAGE_LENGTH)
throw new FormatException();
// Validate timestamp // Validate timestamp
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH); long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
if (timestamp < 0) throw new FormatException(); if (timestamp < 0) throw new FormatException();

View File

@@ -32,7 +32,8 @@ class SessionParserImpl implements SessionParser {
@Override @Override
public Session parseSession(BdfDictionary meta) throws FormatException { public Session parseSession(BdfDictionary meta) throws FormatException {
State state = State.fromValue(meta.getInt(SESSION_KEY_STATE)); State state =
State.fromValue(meta.getLong(SESSION_KEY_STATE).intValue());
MessageId lastLocalMessageId = null; MessageId lastLocalMessageId = null;
byte[] lastLocalMessageIdBytes = byte[] lastLocalMessageIdBytes =
@@ -55,9 +56,9 @@ class SessionParserImpl implements SessionParser {
Long localTimestamp = meta.getOptionalLong(SESSION_KEY_LOCAL_TIMESTAMP); Long localTimestamp = meta.getOptionalLong(SESSION_KEY_LOCAL_TIMESTAMP);
KeySetId keySetId = null; KeySetId keySetId = null;
Integer keySetIdInt = meta.getOptionalInt(SESSION_KEY_KEY_SET_ID); Long keySetIdLong = meta.getOptionalLong(SESSION_KEY_KEY_SET_ID);
if (keySetIdInt != null) { if (keySetIdLong != null) {
keySetId = new KeySetId(keySetIdInt); keySetId = new KeySetId(keySetIdLong.intValue());
} }
return new Session(state, lastLocalMessageId, localKeyPair, return new Session(state, lastLocalMessageId, localKeyPair,

View File

@@ -177,8 +177,8 @@ class TransportKeyAgreementManagerImpl extends BdfIncomingMessageHook
protected DeliveryAction incomingMessage(Transaction txn, Message m, protected DeliveryAction incomingMessage(Transaction txn, Message m,
BdfList body, BdfDictionary meta) BdfList body, BdfDictionary meta)
throws DbException, FormatException { throws DbException, FormatException {
MessageType type = MessageType type = MessageType.fromValue(
MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE)); meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue());
TransportId t = new TransportId(meta.getString(MSG_KEY_TRANSPORT_ID)); TransportId t = new TransportId(meta.getString(MSG_KEY_TRANSPORT_ID));
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
LOG.info("Received " + type + " message for " + t); LOG.info("Received " + type + " message for " + t);

View File

@@ -42,7 +42,7 @@ class TransportKeyAgreementValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getInt(0)); MessageType type = MessageType.fromValue(body.getLong(0).intValue());
if (type == KEY) return validateKeyMessage(m.getTimestamp(), body); if (type == KEY) return validateKeyMessage(m.getTimestamp(), body);
else if (type == ACTIVATE) return validateActivateMessage(body); else if (type == ACTIVATE) return validateActivateMessage(body);
else throw new AssertionError(); else throw new AssertionError();

View File

@@ -301,8 +301,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
BdfList cv = body.getList(i); BdfList cv = body.getList(i);
ClientId clientId = new ClientId(cv.getString(0)); ClientId clientId = new ClientId(cv.getString(0));
int majorVersion = cv.getInt(1); int majorVersion = cv.getLong(1).intValue();
int minorVersion = cv.getInt(2); int minorVersion = cv.getLong(2).intValue();
parsed.add(new ClientVersion(clientId, majorVersion, minorVersion)); parsed.add(new ClientVersion(clientId, majorVersion, minorVersion));
} }
return parsed; return parsed;
@@ -408,8 +408,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
throws FormatException { throws FormatException {
// Client ID, major version, minor version, active // Client ID, major version, minor version, active
ClientId clientId = new ClientId(clientState.getString(0)); ClientId clientId = new ClientId(clientState.getString(0));
int majorVersion = clientState.getInt(1); int majorVersion = clientState.getLong(1).intValue();
int minorVersion = clientState.getInt(2); int minorVersion = clientState.getLong(2).intValue();
boolean active = clientState.getBoolean(3); boolean active = clientState.getBoolean(3);
return new ClientState(clientId, majorVersion, minorVersion, active); return new ClientState(clientId, majorVersion, minorVersion, active);
} }

View File

@@ -43,9 +43,9 @@ class ClientVersioningValidator extends BdfMessageValidator {
checkSize(clientState, 4); checkSize(clientState, 4);
String clientId = clientState.getString(0); String clientId = clientState.getString(0);
checkLength(clientId, 1, MAX_CLIENT_ID_LENGTH); checkLength(clientId, 1, MAX_CLIENT_ID_LENGTH);
int majorVersion = clientState.getInt(1); int majorVersion = clientState.getLong(1).intValue();
if (majorVersion < 0) throw new FormatException(); if (majorVersion < 0) throw new FormatException();
int minorVersion = clientState.getInt(2); int minorVersion = clientState.getLong(2).intValue();
if (minorVersion < 0) throw new FormatException(); if (minorVersion < 0) throw new FormatException();
clientState.getBoolean(3); clientState.getBoolean(3);
} }

View File

@@ -56,7 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE)); will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
oneOf(clientHelper).toList(message, true); oneOf(clientHelper).toList(message.getBody());
will(returnValue(body)); will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta)); will(returnValue(meta));
@@ -86,7 +86,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(shortMessage, true); oneOf(clientHelper).toList(shortMessage.getBody());
will(returnValue(body)); will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta)); will(returnValue(meta));
@@ -114,7 +114,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(message, true); oneOf(clientHelper).toList(message.getBody());
will(throwException(new FormatException())); will(throwException(new FormatException()));
}}); }});
@@ -126,7 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(message, true); oneOf(clientHelper).toList(message.getBody());
will(returnValue(body)); will(returnValue(body));
}}); }});

View File

@@ -546,7 +546,7 @@ public class ClientHelperImplTest extends BrambleMockTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(bdfReaderFactory) oneOf(bdfReaderFactory)
.createReader(with(any(InputStream.class)), with(true)); .createReader(with(any(InputStream.class)));
will(returnValue(bdfReader)); will(returnValue(bdfReader));
oneOf(bdfReader).readList(); oneOf(bdfReader).readList();
will(returnValue(list)); will(returnValue(list));

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.data; package org.briarproject.bramble.data;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -32,14 +31,11 @@ public class BdfReaderImplFuzzingTest extends BrambleTestCase {
buf[1] = 0x14; // Length 20 bytes buf[1] = 0x14; // Length 20 bytes
in.reset(); in.reset();
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, true); DEFAULT_MAX_BUFFER_SIZE);
try { int length = r.readString().length();
int length = r.readString().length(); assertTrue(length >= 0);
assertTrue(length <= 20); assertTrue(length <= 20);
assertTrue(r.eof()); assertTrue(r.eof());
} catch (FormatException e) {
// Expected when bytes are not valid UTF-8
}
} }
} }
} }

View File

@@ -11,7 +11,6 @@ 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.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.UTF_8;
import static org.briarproject.bramble.util.StringUtils.fromHexString; import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.bramble.util.StringUtils.toHexString; import static org.briarproject.bramble.util.StringUtils.toHexString;
@@ -89,18 +88,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test(expected = FormatException.class)
public void testReadLong16CouldHaveBeenLong8Max() throws Exception {
setContents("22" + "007F");
r.readLong();
}
@Test(expected = FormatException.class)
public void testReadLong16CouldHaveBeenLong8Min() throws Exception {
setContents("22" + "FF80");
r.readLong();
}
@Test @Test
public void testSkipLong16() throws Exception { public void testSkipLong16() throws Exception {
setContents("22" + "0080"); setContents("22" + "0080");
@@ -119,18 +106,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test(expected = FormatException.class)
public void testReadLong32CouldHaveBeenLong16Max() throws Exception {
setContents("24" + "00007FFF");
r.readLong();
}
@Test(expected = FormatException.class)
public void testReadLong32CouldHaveBeenLong16Min() throws Exception {
setContents("24" + "FFFF8000");
r.readLong();
}
@Test @Test
public void testSkipLong32() throws Exception { public void testSkipLong32() throws Exception {
setContents("24" + "00008000"); setContents("24" + "00008000");
@@ -149,48 +124,13 @@ public class BdfReaderImplTest extends BrambleTestCase {
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test(expected = FormatException.class)
public void testReadLong64CouldHaveBeenLong32Max() throws Exception {
setContents("28" + "000000007FFFFFFF");
r.readLong();
}
@Test(expected = FormatException.class)
public void testReadLong64CouldHaveBeenLong32Min() throws Exception {
setContents("28" + "FFFFFFFF80000000");
r.readLong();
}
@Test @Test
public void testSkipLong64() throws Exception { public void testSkipLong() throws Exception {
setContents("28" + "0000000080000000"); setContents("28" + "0000000080000000");
r.skipLong(); r.skipLong();
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test
public void testReadInt() throws Exception {
setContents("21" + "7F" + "21" + "80"
+ "22" + "7FFF" + "22" + "8000"
+ "24" + "7FFFFFFF" + "24" + "80000000");
assertEquals(Byte.MAX_VALUE, r.readInt());
assertEquals(Byte.MIN_VALUE, r.readInt());
assertEquals(Short.MAX_VALUE, r.readInt());
assertEquals(Short.MIN_VALUE, r.readInt());
assertEquals(Integer.MAX_VALUE, r.readInt());
assertEquals(Integer.MIN_VALUE, r.readInt());
assertTrue(r.eof());
}
@Test
public void testSkipInt() throws Exception {
setContents("21" + "7F" + "22" + "7FFF" + "24" + "7FFFFFFF");
r.skipInt();
r.skipInt();
r.skipInt();
assertTrue(r.eof());
}
@Test @Test
public void testReadDouble() throws Exception { public void testReadDouble() throws Exception {
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html // http://babbage.cs.qc.edu/IEEE-754/Decimal.html
@@ -222,7 +162,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadString8() throws Exception { public void testReadString8() throws Exception {
String longest = getRandomString(Byte.MAX_VALUE); String longest = getRandomString(Byte.MAX_VALUE);
String longHex = 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);
@@ -246,7 +186,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testSkipString8() throws Exception { public void testSkipString8() throws Exception {
String longest = getRandomString(Byte.MAX_VALUE); String longest = getRandomString(Byte.MAX_VALUE);
String longHex = 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);
@@ -259,9 +199,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadString16() throws Exception { public void testReadString16() throws Exception {
String shortest = getRandomString(Byte.MAX_VALUE + 1); String shortest = getRandomString(Byte.MAX_VALUE + 1);
String shortHex = toHexString(shortest.getBytes(UTF_8)); String shortHex = toHexString(shortest.getBytes("UTF-8"));
String longest = getRandomString(Short.MAX_VALUE); String longest = getRandomString(Short.MAX_VALUE);
String longHex = 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()); assertEquals(shortest, r.readString());
@@ -273,7 +213,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
public void testReadString16ChecksMaxLength() throws Exception { public void testReadString16ChecksMaxLength() throws Exception {
int maxBufferSize = Byte.MAX_VALUE + 1; int maxBufferSize = Byte.MAX_VALUE + 1;
String valid = getRandomString(Byte.MAX_VALUE + 1); String valid = getRandomString(Byte.MAX_VALUE + 1);
String validHex = toHexString(valid.getBytes(UTF_8)); String validHex = toHexString(valid.getBytes("UTF-8"));
String invalidhex = validHex + "20"; String invalidhex = validHex + "20";
// 128 random letters, the same plus a space // 128 random letters, the same plus a space
setContents("42" + "0080" + validHex setContents("42" + "0080" + validHex
@@ -283,20 +223,12 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readString(); r.readString();
} }
@Test(expected = FormatException.class)
public void testReadString16CouldHaveBeenString8() throws Exception {
String longest = getRandomString(Byte.MAX_VALUE);
String longHex = toHexString(longest.getBytes(UTF_8));
setContents("42" + "007F" + longHex);
r.readString();
}
@Test @Test
public void testSkipString16() throws Exception { public void testSkipString16() throws Exception {
String shortest = getRandomString(Byte.MAX_VALUE + 1); String shortest = getRandomString(Byte.MAX_VALUE + 1);
String shortHex = toHexString(shortest.getBytes(UTF_8)); String shortHex = toHexString(shortest.getBytes("UTF-8"));
String longest = getRandomString(Short.MAX_VALUE); String longest = getRandomString(Short.MAX_VALUE);
String longHex = 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();
@@ -307,7 +239,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadString32() throws Exception { public void testReadString32() throws Exception {
String shortest = getRandomString(Short.MAX_VALUE + 1); String shortest = getRandomString(Short.MAX_VALUE + 1);
String shortHex = 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()); assertEquals(shortest, r.readString());
@@ -318,7 +250,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
public void testReadString32ChecksMaxLength() throws Exception { public void testReadString32ChecksMaxLength() throws Exception {
int maxBufferSize = Short.MAX_VALUE + 1; int maxBufferSize = Short.MAX_VALUE + 1;
String valid = getRandomString(maxBufferSize); String valid = getRandomString(maxBufferSize);
String validHex = toHexString(valid.getBytes(UTF_8)); String validHex = toHexString(valid.getBytes("UTF-8"));
String invalidHex = validHex + "20"; String invalidHex = validHex + "20";
// 2^15 random letters, the same plus a space // 2^15 random letters, the same plus a space
setContents("44" + "00008000" + validHex + setContents("44" + "00008000" + validHex +
@@ -328,18 +260,10 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readString(); r.readString();
} }
@Test(expected = FormatException.class)
public void testReadString32CouldHaveBeenString16() throws Exception {
String longest = getRandomString(Short.MAX_VALUE);
String longHex = toHexString(longest.getBytes(UTF_8));
setContents("44" + "00007FFF" + longHex);
r.readString();
}
@Test @Test
public void testSkipString32() throws Exception { public void testSkipString32() throws Exception {
String shortest = getRandomString(Short.MAX_VALUE + 1); String shortest = getRandomString(Short.MAX_VALUE + 1);
String shortHex = 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);
@@ -351,7 +275,7 @@ 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 = 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()); assertEquals("foo", r.readString());
@@ -424,14 +348,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readRaw(); r.readRaw();
} }
@Test(expected = FormatException.class)
public void testReadRaw16CouldHaveBeenRaw8() throws Exception {
byte[] longest = new byte[Byte.MAX_VALUE];
String longHex = toHexString(longest);
setContents("52" + "007F" + longHex);
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];
@@ -469,14 +385,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readRaw(); r.readRaw();
} }
@Test(expected = FormatException.class)
public void testReadRaw32CouldHaveBeenRaw16() throws Exception {
byte[] longest = new byte[Short.MAX_VALUE];
String longHex = toHexString(longest);
setContents("54" + "00007FFF" + longHex);
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];
@@ -526,6 +434,25 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readList(); r.readList();
} }
@Test
public void testReadListManually() throws Exception {
// A list containing 1, "foo", and null
setContents("60" + "21" + "01" +
"41" + "03" + "666F6F" +
"00" + "80");
r.readListStart();
assertFalse(r.hasListEnd());
assertEquals(1, r.readLong());
assertFalse(r.hasListEnd());
assertEquals("foo", r.readString());
assertFalse(r.hasListEnd());
assertTrue(r.hasNull());
r.readNull();
assertTrue(r.hasListEnd());
r.readListEnd();
assertTrue(r.eof());
}
@Test @Test
public void testSkipList() throws Exception { public void testSkipList() throws Exception {
// A list containing 1, "foo", and 128 // A list containing 1, "foo", and 128
@@ -538,9 +465,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadDictionary() throws Exception { public void testReadDictionary() throws Exception {
// A dictionary containing "bar" -> null and "foo" -> 123 // A dictionary containing "foo" -> 123 and "bar" -> null
setContents("70" + "41" + "03" + "626172" + "00" + setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
"41" + "03" + "666F6F" + "21" + "7B" + "80"); "41" + "03" + "626172" + "00" + "80");
BdfDictionary dictionary = r.readDictionary(); BdfDictionary dictionary = r.readDictionary();
assertEquals(2, dictionary.size()); assertEquals(2, dictionary.size());
assertTrue(dictionary.containsKey("foo")); assertTrue(dictionary.containsKey("foo"));
@@ -590,6 +517,26 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readDictionary(); r.readDictionary();
} }
@Test
public void testReadDictionaryManually() throws Exception {
// A dictionary containing "foo" -> 123 and "bar" -> null
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
"41" + "03" + "626172" + "00" + "80");
r.readDictionaryStart();
assertFalse(r.hasDictionaryEnd());
assertEquals("foo", r.readString());
assertFalse(r.hasDictionaryEnd());
assertEquals(123, r.readLong());
assertFalse(r.hasDictionaryEnd());
assertEquals("bar", r.readString());
assertFalse(r.hasDictionaryEnd());
assertTrue(r.hasNull());
r.readNull();
assertTrue(r.hasDictionaryEnd());
r.readDictionaryEnd();
assertTrue(r.eof());
}
@Test @Test
public void testSkipDictionary() throws Exception { public void testSkipDictionary() throws Exception {
// A map containing "foo" -> 123 and "bar" -> null // A map containing "foo" -> 123 and "bar" -> null
@@ -610,10 +557,10 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testNestedListWithinDepthLimit() throws Exception { public void testNestedListWithinDepthLimit() throws Exception {
// A list containing a list containing a list containing a list... // A list containing a list containing a list containing a list...
StringBuilder lists = new StringBuilder(); String lists = "";
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists.append("60"); for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists += "60";
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists.append("80"); for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists += "80";
setContents(lists.toString()); setContents(lists);
r.readList(); r.readList();
assertTrue(r.eof()); assertTrue(r.eof());
} }
@@ -621,25 +568,23 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNestedListOutsideDepthLimit() throws Exception { public void testNestedListOutsideDepthLimit() throws Exception {
// A list containing a list containing a list containing a list... // A list containing a list containing a list containing a list...
StringBuilder lists = new StringBuilder(); String lists = "";
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists.append("60"); for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists += "60";
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists.append("80"); for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists += "80";
setContents(lists.toString()); setContents(lists);
r.readList(); r.readList();
} }
@Test @Test
public void testNestedDictionaryWithinDepthLimit() throws Exception { public void testNestedDictionaryWithinDepthLimit() throws Exception {
// A dictionary containing a dictionary containing a dictionary... // A dictionary containing a dictionary containing a dictionary...
StringBuilder dicts = new StringBuilder(); String dicts = "";
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) { for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++)
dicts.append("70").append("41").append("03").append("666F6F"); dicts += "70" + "41" + "03" + "666F6F";
} dicts += "11";
dicts.append("11"); for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++)
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) { dicts += "80";
dicts.append("80"); setContents(dicts);
}
setContents(dicts.toString());
r.readDictionary(); r.readDictionary();
assertTrue(r.eof()); assertTrue(r.eof());
} }
@@ -647,15 +592,13 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNestedDictionaryOutsideDepthLimit() throws Exception { public void testNestedDictionaryOutsideDepthLimit() throws Exception {
// A dictionary containing a dictionary containing a dictionary... // A dictionary containing a dictionary containing a dictionary...
StringBuilder dicts = new StringBuilder(); String dicts = "";
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) { for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++)
dicts.append("70").append("41").append("03").append("666F6F"); dicts += "70" + "41" + "03" + "666F6F";
} dicts += "11";
dicts.append("11"); for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++)
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) { dicts += "80";
dicts.append("80"); setContents(dicts);
}
setContents(dicts.toString());
r.readDictionary(); r.readDictionary();
} }
@@ -682,6 +625,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
private void setContents(String hex, int maxBufferSize) private void setContents(String hex, int maxBufferSize)
throws FormatException { throws FormatException {
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex)); ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize, true); r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize);
} }
} }

View File

@@ -1,80 +0,0 @@
package org.briarproject.bramble.data;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfReader;
import org.briarproject.bramble.api.data.BdfWriter;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
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.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class BdfReaderWriterIntegrationTest extends BrambleTestCase {
@Test
public void testConvertStringToCanonicalForm() throws Exception {
// 'foo' as a STRING_16 (not canonical, should be a STRING_8)
String hexIn = "42" + "0003" + "666F6F";
InputStream in = new ByteArrayInputStream(fromHexString(hexIn));
BdfReader r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, false); // Accept non-canonical
String s = r.readString();
assertEquals("foo", s);
assertTrue(r.eof());
// Convert the string back to BDF
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = new BdfWriterImpl(out);
w.writeString(s);
w.flush();
String hexOut = toHexString(out.toByteArray());
// The BDF should now be in canonical form
assertEquals("41" + "03" + "666F6F", hexOut);
}
@Test
public void testConvertDictionaryToCanonicalForm() throws Exception {
// A dictionary with keys in non-canonical order: 'foo' then 'bar'
String hexIn = "70" + "41" + "03" + "666F6F" + "21" + "01"
+ "41" + "03" + "626172" + "21" + "02" + "80";
InputStream in = new ByteArrayInputStream(fromHexString(hexIn));
BdfReader r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, false); // Accept non-canonical
BdfDictionary d = r.readDictionary();
assertEquals(2, d.size());
assertTrue(r.eof());
// The entries should be returned in canonical order
Iterator<Entry<String, Object>> it = d.entrySet().iterator();
Entry<String, Object> first = it.next();
assertEquals("bar", first.getKey());
assertEquals(2L, first.getValue());
Entry<String, Object> second = it.next();
assertEquals("foo", second.getKey());
assertEquals(1L, second.getValue());
// Convert a non-canonical map to BDF (use LinkedHashMap so we know
// the entries will be iterated over in non-canonical order)
Map<String, Object> m = new LinkedHashMap<>();
m.put("foo", 1);
m.put("bar", 2);
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = new BdfWriterImpl(out);
w.writeDictionary(m);
w.flush();
String hexOut = toHexString(out.toByteArray());
// The entries should be in canonical order: 'bar' then 'foo'
assertEquals("70" + "41" + "03" + "626172" + "21" + "02"
+ "41" + "03" + "666F6F" + "21" + "01" + "80", hexOut);
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.data; package org.briarproject.bramble.data;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import org.junit.Test; import org.junit.Test;
@@ -169,11 +168,9 @@ public class BdfWriterImplTest extends BrambleTestCase {
@Test @Test
public void testWriteDictionary() throws IOException { public void testWriteDictionary() throws IOException {
// Add entries to dictionary in descending order - they should be // Use LinkedHashMap to get predictable iteration order
// output in ascending order. Use LinkedHashMap to get predictable
// iteration order
Map<String, Object> m = new LinkedHashMap<>(); Map<String, Object> m = new LinkedHashMap<>();
for (int i = 3; i >= 0; i--) m.put(String.valueOf(i), i); for (int i = 0; i < 4; i++) m.put(String.valueOf(i), i);
w.writeDictionary(m); w.writeDictionary(m);
// DICTIONARY tag, keys as strings and values as integers, END tag // DICTIONARY tag, keys as strings and values as integers, END tag
checkContents("70" + "41" + "01" + "30" + "21" + "00" + checkContents("70" + "41" + "01" + "30" + "21" + "00" +
@@ -183,17 +180,30 @@ public class BdfWriterImplTest extends BrambleTestCase {
} }
@Test @Test
public void testWriteBdfDictionary() throws IOException { public void testWriteDelimitedList() throws IOException {
// Add entries to dictionary in descending order - they should be w.writeListStart();
// output in ascending order w.writeLong(1);
BdfDictionary d = new BdfDictionary(); w.writeString("foo");
for (int i = 3; i >= 0; i--) d.put(String.valueOf(i), i); w.writeLong(128);
w.writeDictionary(d); w.writeListEnd();
// DICTIONARY tag, keys as strings and values as integers, END tag // LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag
checkContents("70" + "41" + "01" + "30" + "21" + "00" + checkContents("60" + "21" + "01" +
"41" + "01" + "31" + "21" + "01" + "41" + "03" + "666F6F" +
"41" + "01" + "32" + "21" + "02" + "22" + "0080" + "80");
"41" + "01" + "33" + "21" + "03" + "80"); }
@Test
public void testWriteDelimitedDictionary() throws IOException {
w.writeDictionaryStart();
w.writeString("foo");
w.writeLong(123);
w.writeString("bar");
w.writeNull();
w.writeDictionaryEnd();
// DICTIONARY tag, "foo" as string, 123 as integer, "bar" as string,
// NULL tag, END tag
checkContents("70" + "41" + "03" + "666F6F" +
"21" + "7B" + "41" + "03" + "626172" + "00" + "80");
} }
@Test @Test

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.mailbox; package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
@@ -10,23 +9,17 @@ import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEven
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.util.Base32;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.util.Locale;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS; import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties; import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.hasEvent; import static org.briarproject.bramble.test.TestUtils.hasEvent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class MailboxManagerImplTest extends BrambleMockTestCase { public class MailboxManagerImplTest extends BrambleMockTestCase {
@@ -132,32 +125,4 @@ public class MailboxManagerImplTest extends BrambleMockTestCase {
assertTrue(manager.checkConnection()); assertTrue(manager.checkConnection());
} }
@Test
public void testConvertBase32Payload() throws FormatException {
byte[] payload = getRandomBytes(65);
String base32payload = Base32.encode(payload).toLowerCase(Locale.ROOT);
String expected = new String(payload, ISO_8859_1);
try {
manager.convertBase32Payload("foo bar");
fail();
} catch (FormatException e) {
// expected
}
try { // doesn't work with shorter link
manager.convertBase32Payload("briar-mailbox://" +
base32payload.substring(0, base32payload.length() - 1));
fail();
} catch (FormatException e) {
// expected
}
// works with white-spaces
assertEquals(expected, manager.convertBase32Payload(
"foo bar briar-mailbox://" + base32payload + " foo bar"));
// even works without white-space at the end
assertEquals(expected, manager.convertBase32Payload(
"foo bar briar-mailbox://" + base32payload + "foobar"));
// even works without schema and extra chars at end
assertEquals(expected, manager.convertBase32Payload(
"foo bar " + base32payload + "foobar"));
}
} }

View File

@@ -217,13 +217,13 @@ public class LanTcpPluginTest extends BrambleTestCase {
// The plugin should have bound a socket and stored the port number // The plugin should have bound a socket and stored the port number
BdfList descriptor = kal.getDescriptor(); BdfList descriptor = kal.getDescriptor();
assertEquals(3, descriptor.size()); assertEquals(3, descriptor.size());
assertEquals(TRANSPORT_ID_LAN, descriptor.getInt(0).intValue()); assertEquals(TRANSPORT_ID_LAN, descriptor.getLong(0).longValue());
byte[] address = descriptor.getRaw(1); byte[] address = descriptor.getRaw(1);
InetAddress addr = InetAddress.getByAddress(address); InetAddress addr = InetAddress.getByAddress(address);
assertTrue(addr instanceof Inet4Address); assertTrue(addr instanceof Inet4Address);
assertFalse(addr.isLoopbackAddress()); assertFalse(addr.isLoopbackAddress());
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress()); assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
int port = descriptor.getInt(2); int port = descriptor.getLong(2).intValue();
assertTrue(port > 0 && port < 65536); assertTrue(port > 0 && port < 65536);
// The plugin should be listening on the port // The plugin should be listening on the port
InetSocketAddress socketAddr = new InetSocketAddress(addr, port); InetSocketAddress socketAddr = new InetSocketAddress(addr, port);

View File

@@ -404,7 +404,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId, false); oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -471,7 +471,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup2.getId()); contactGroup2.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId, false); oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -526,7 +526,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, updateId, false); oneOf(clientHelper).getMessageAsList(txn, updateId);
will(returnValue(update)); will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -564,7 +564,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, updateId, false); oneOf(clientHelper).getMessageAsList(txn, updateId);
will(returnValue(update)); will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -695,8 +695,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(localGroupMessageMetadata)); will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId, oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
false);
will(returnValue(oldUpdate)); will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict); oldPropertiesDict);
@@ -761,8 +760,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(localGroupMessageMetadata)); will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId, oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
false);
will(returnValue(oldUpdate)); will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict); oldPropertiesDict);
@@ -821,12 +819,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
oneOf(clientHelper).getMessageAsList(txn, fooVersion999, false); oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
will(returnValue(fooProperties)); will(returnValue(fooProperties));
oneOf(clientHelper).getMessageAsList(txn, barVersion3, false); oneOf(clientHelper).getMessageAsList(txn, barVersion3);
will(returnValue(barUpdate)); will(returnValue(barUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
barPropertiesDict); barPropertiesDict);

View File

@@ -6,18 +6,13 @@ import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.record.Record; import org.briarproject.bramble.api.record.Record;
import org.briarproject.bramble.api.record.RecordReader; import org.briarproject.bramble.api.record.RecordReader;
import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory; import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Priority; import org.briarproject.bramble.api.sync.Priority;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordReader; import org.briarproject.bramble.api.sync.SyncRecordReader;
import org.briarproject.bramble.api.sync.Versions; import org.briarproject.bramble.api.sync.Versions;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.PredicateMatcher;
import org.hamcrest.Matcher;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
@@ -28,15 +23,12 @@ import javax.annotation.Nullable;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
import static org.briarproject.bramble.api.sync.RecordTypes.ACK; import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE;
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER; import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY; import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS; import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES; import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
@@ -54,38 +46,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
private final SyncRecordReader reader = private final SyncRecordReader reader =
new SyncRecordReaderImpl(messageFactory, recordReader); new SyncRecordReaderImpl(messageFactory, recordReader);
@Test
public void testNoFormatExceptionIfMessageIsMinimumSize() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH + 1));
expectCreateMessage(1);
reader.readMessage();
}
@Test(expected = FormatException.class)
public void testFormatExceptionIfMessageIsTooSmall() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH));
reader.readMessage();
}
@Test
public void testNoFormatExceptionIfMessageIsMaximumSize() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH
+ MAX_MESSAGE_BODY_LENGTH));
expectCreateMessage(MAX_MESSAGE_BODY_LENGTH);
reader.readMessage();
}
@Test(expected = FormatException.class)
public void testFormatExceptionIfMessageIsTooLarge() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH
+ MAX_MESSAGE_BODY_LENGTH + 1));
reader.readMessage();
}
@Test @Test
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception { public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
expectReadRecord(createAck()); expectReadRecord(createAck());
@@ -198,20 +158,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
assertTrue(reader.eof()); assertTrue(reader.eof());
} }
private void expectCreateMessage(int bodyLength) {
MessageId messageId = new MessageId(getRandomId());
GroupId groupId = new GroupId(getRandomId());
long timestamp = System.currentTimeMillis();
context.checking(new Expectations() {{
Matcher<byte[]> matcher = new PredicateMatcher<>(byte[].class,
b -> b.length == MESSAGE_HEADER_LENGTH + bodyLength);
oneOf(messageFactory).createMessage(with(matcher));
will(returnValue(new Message(messageId, groupId, timestamp,
new byte[bodyLength])));
}});
}
private void expectReadRecord(@Nullable Record record) throws Exception { private void expectReadRecord(@Nullable Record record) throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
//noinspection unchecked //noinspection unchecked
@@ -221,10 +167,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
}}); }});
} }
private Record createMessage(int payloadLength) {
return new Record(PROTOCOL_VERSION, MESSAGE, new byte[payloadLength]);
}
private Record createAck() throws Exception { private Record createAck() throws Exception {
return new Record(PROTOCOL_VERSION, ACK, createPayload()); return new Record(PROTOCOL_VERSION, ACK, createPayload());
} }

View File

@@ -88,58 +88,51 @@ public class StringUtilsTest extends BrambleTestCase {
} }
@Test @Test
public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8() public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8() {
throws Exception {
// The UTF-8 encoding of the null character is valid // The UTF-8 encoding of the null character is valid
byte[] utf8 = new byte[1]; assertEquals("\u0000", StringUtils.fromUtf8(new byte[1]));
String actual = StringUtils.fromUtf8(utf8);
assertEquals("\u0000", actual);
// When we convert back to UTF-8 we should get the original encoding
assertArrayEquals(utf8, StringUtils.toUtf8(actual));
} }
@Test(expected = FormatException.class) @Test
public void testFromUtf8RejectsNullCharacterUsingModifiedUtf8() public void testFromUtf8RemovesNullCharacterUsingModifiedUtf8() {
throws Exception {
// The modified UTF-8 encoding of the null character is not valid // The modified UTF-8 encoding of the null character is not valid
byte[] b = new byte[] { byte[] b = new byte[] {
(byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8 (byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8
(byte) 0xC8, (byte) 0x85 // U+0205 (byte) 0xC8, (byte) 0x85 // U+0205
}; };
StringUtils.fromUtf8(b); // Conversion should ignore the invalid character and return the rest
String expected = "\u0205";
assertEquals(expected, StringUtils.fromUtf8(b));
} }
@Test @Test
public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8() public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8() {
throws Exception {
// The UTF-8 encoding of a supplementary character is valid and should // The UTF-8 encoding of a supplementary character is valid and should
// be converted to a surrogate pair // be converted to a surrogate pair
byte[] utf8 = new byte[] { byte[] b = new byte[] {
(byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400 (byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400
(byte) 0xC8, (byte) 0x85 // U+0205 (byte) 0xC8, (byte) 0x85 // U+0205
}; };
String expected = "\uD801\uDC00\u0205"; // Surrogate pair String expected = "\uD801\uDC00\u0205"; // Surrogate pair
String actual = StringUtils.fromUtf8(utf8); assertEquals(expected, StringUtils.fromUtf8(b));
assertEquals(expected, actual);
// When we convert back to UTF-8 we should get the original encoding
assertArrayEquals(utf8, StringUtils.toUtf8(actual));
} }
@Test(expected = FormatException.class) @Test
public void testFromUtf8RejectsSupplementaryCharacterUsingModifiedUtf8() public void testFromUtf8RemovesSupplementaryCharacterUsingModifiedUtf8() {
throws Exception {
// The CESU-8 or modified UTF-8 encoding of a supplementary character // The CESU-8 or modified UTF-8 encoding of a supplementary character
// is not valid // is not valid
byte[] utf8 = new byte[] { byte[] b = new byte[] {
(byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8 (byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8
(byte) 0xED, (byte) 0xB0, (byte) 0x80, (byte) 0xED, (byte) 0xB0, (byte) 0x80,
(byte) 0xC8, (byte) 0x85 // U+0205 (byte) 0xC8, (byte) 0x85 // U+0205
}; };
StringUtils.fromUtf8(utf8); // Conversion should ignore the invalid character and return the rest
String expected = "\u0205";
assertEquals(expected, StringUtils.fromUtf8(b));
} }
@Test @Test
public void testFromUtf8EmptyInput() throws Exception { public void testFromUtf8EmptyInput() {
assertEquals("", StringUtils.fromUtf8(new byte[0])); assertEquals("", StringUtils.fromUtf8(new byte[0]));
} }

View File

@@ -26,8 +26,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 31 targetSdkVersion 31
versionCode 10422 versionCode 10420
versionName "1.4.22" versionName "1.4.20"
applicationId "org.briarproject.briar.android" applicationId "org.briarproject.briar.android"
buildConfigField "String", "TorVersion", "\"$tor_version\"" buildConfigField "String", "TorVersion", "\"$tor_version\""

View File

@@ -5,25 +5,16 @@ import android.os.Bundle;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.blog.RssImportResult.FileImportError;
import org.briarproject.briar.android.blog.RssImportResult.FileImportSuccess;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportError;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportSuccess;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.fragment.ErrorFragment;
import org.briarproject.nullsafety.MethodsNotNullByDefault; import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault; import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import static androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
import static org.briarproject.briar.android.util.UiUtils.showFragment;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class RssFeedActivity extends BriarActivity public class RssFeedActivity extends BriarActivity
@@ -54,29 +45,21 @@ public class RssFeedActivity extends BriarActivity
viewModel.getImportResult().observeEvent(this, this::onImportResult); viewModel.getImportResult().observeEvent(this, this::onImportResult);
} }
private void onImportResult(@Nullable RssImportResult result) { private void onImportResult(boolean result) {
FragmentManager fm = getSupportFragmentManager(); if (result) {
if (result instanceof UrlImportSuccess) { FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentByTag(RssFeedImportFragment.TAG) != null) { if (fm.findFragmentByTag(RssFeedImportFragment.TAG) != null) {
onBackPressed(); onBackPressed();
} }
} else if (result instanceof UrlImportError) { } else {
String url = ((UrlImportError) result).url; String url = viewModel.getUrlFailedImport();
if (url == null) {
throw new AssertionError();
}
RssFeedImportFailedDialogFragment dialog = RssFeedImportFailedDialogFragment dialog =
RssFeedImportFailedDialogFragment.newInstance(url); RssFeedImportFailedDialogFragment.newInstance(url);
dialog.show(fm, RssFeedImportFailedDialogFragment.TAG); dialog.show(getSupportFragmentManager(),
} else if (result instanceof FileImportSuccess) { RssFeedImportFailedDialogFragment.TAG);
// pop stack back to before the initial import fragment
fm.popBackStackImmediate(RssFeedImportFragment.TAG,
POP_BACK_STACK_INCLUSIVE);
} else if (result instanceof FileImportError) {
// pop stack back to initial import fragment
fm.popBackStackImmediate(RssFeedImportFragment.TAG, 0);
// show error fragment
Fragment f = ErrorFragment.newInstance(
getString(R.string.blogs_rss_feeds_import_error));
String tag = ErrorFragment.TAG;
showFragment(fm, f, tag);
} }
} }
} }

View File

@@ -1,13 +1,9 @@
package org.briarproject.briar.android.blog; package org.briarproject.briar.android.blog;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
@@ -17,27 +13,18 @@ import android.widget.ProgressBar;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.ProgressFragment;
import org.briarproject.briar.android.util.ActivityLaunchers.GetContentAdvanced;
import org.briarproject.briar.android.util.ActivityLaunchers.OpenDocumentAdvanced;
import org.briarproject.nullsafety.MethodsNotNullByDefault; import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault; import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import static android.os.Build.VERSION.SDK_INT;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard; import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
import static org.briarproject.briar.android.util.UiUtils.showFragment;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -52,15 +39,6 @@ public class RssFeedImportFragment extends BaseFragment {
private Button importButton; private Button importButton;
private ProgressBar progressBar; private ProgressBar progressBar;
@RequiresApi(19)
private final ActivityResultLauncher<String[]> docLauncher =
registerForActivityResult(new OpenDocumentAdvanced(),
this::onFileChosen);
private final ActivityResultLauncher<String> contentLauncher =
registerForActivityResult(new GetContentAdvanced(),
this::onFileChosen);
@Override @Override
public void injectFragment(ActivityComponent component) { public void injectFragment(ActivityComponent component) {
component.inject(this); component.inject(this);
@@ -74,7 +52,6 @@ public class RssFeedImportFragment extends BaseFragment {
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import)); requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import));
if (SDK_INT >= 19) setHasOptionsMenu(true);
View v = inflater.inflate(R.layout.fragment_rss_feed_import, View v = inflater.inflate(R.layout.fragment_rss_feed_import,
container, false); container, false);
@@ -115,40 +92,11 @@ public class RssFeedImportFragment extends BaseFragment {
return v; return v;
} }
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (SDK_INT >= 19) {
inflater.inflate(R.menu.rss_feed_import_actions, menu);
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_import_file && SDK_INT >= 19) {
launchActivityToOpenFile(requireContext(), docLauncher,
contentLauncher, "*/*");
return true;
}
return super.onOptionsItemSelected(item);
}
@Override @Override
public String getUniqueTag() { public String getUniqueTag() {
return TAG; return TAG;
} }
private void onFileChosen(@Nullable Uri uri) {
if (uri == null) return;
// show progress fragment
Fragment f = ProgressFragment.newInstance(
getString(R.string.blogs_rss_feeds_import_progress));
String tag = ProgressFragment.TAG;
showFragment(getParentFragmentManager(), f, tag);
// view model will import and change state that activity will react to
viewModel.importFeed(uri);
}
private void enableOrDisableImportButton() { private void enableOrDisableImportButton() {
String url = urlInput.getText().toString(); String url = urlInput.getText().toString();
importButton.setEnabled(viewModel.validateAndNormaliseUrl(url) != null); importButton.setEnabled(viewModel.validateAndNormaliseUrl(url) != null);

View File

@@ -1,8 +1,6 @@
package org.briarproject.briar.android.blog; package org.briarproject.briar.android.blog;
import android.app.Application; import android.app.Application;
import android.content.ContentResolver;
import android.net.Uri;
import android.util.Patterns; import android.util.Patterns;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
@@ -13,10 +11,6 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.android.blog.RssImportResult.FileImportError;
import org.briarproject.briar.android.blog.RssImportResult.FileImportSuccess;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportError;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportSuccess;
import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.LiveResult; import org.briarproject.briar.android.viewmodel.LiveResult;
@@ -26,7 +20,6 @@ import org.briarproject.briar.api.feed.FeedManager;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
@@ -37,7 +30,6 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
@@ -60,9 +52,11 @@ class RssFeedViewModel extends DbViewModel {
private final MutableLiveData<LiveResult<List<Feed>>> feeds = private final MutableLiveData<LiveResult<List<Feed>>> feeds =
new MutableLiveData<>(); new MutableLiveData<>();
@Nullable
private volatile String urlFailedImport = null;
private final MutableLiveData<Boolean> isImporting = private final MutableLiveData<Boolean> isImporting =
new MutableLiveData<>(false); new MutableLiveData<>(false);
private final MutableLiveEvent<RssImportResult> importResult = private final MutableLiveEvent<Boolean> importResult =
new MutableLiveEvent<>(); new MutableLiveEvent<>();
@Inject @Inject
@@ -126,7 +120,7 @@ class RssFeedViewModel extends DbViewModel {
}); });
} }
LiveEvent<RssImportResult> getImportResult() { LiveEvent<Boolean> getImportResult() {
return importResult; return importResult;
} }
@@ -136,6 +130,7 @@ class RssFeedViewModel extends DbViewModel {
void importFeed(String url) { void importFeed(String url) {
isImporting.setValue(true); isImporting.setValue(true);
urlFailedImport = null;
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
try { try {
Feed feed = feedManager.addFeed(url); Feed feed = feedManager.addFeed(url);
@@ -150,38 +145,19 @@ class RssFeedViewModel extends DbViewModel {
updated = feedList; updated = feedList;
} }
feeds.postValue(new LiveResult<>(updated)); feeds.postValue(new LiveResult<>(updated));
importResult.postEvent(new UrlImportSuccess()); importResult.postEvent(true);
} catch (DbException | IOException e) { } catch (DbException | IOException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
importResult.postEvent(new UrlImportError(url)); urlFailedImport = url;
importResult.postEvent(false);
} finally { } finally {
isImporting.postValue(false); isImporting.postValue(false);
} }
}); });
} }
@UiThread @Nullable
void importFeed(Uri uri) { String getUrlFailedImport() {
ContentResolver contentResolver = getApplication().getContentResolver(); return urlFailedImport;
ioExecutor.execute(() -> {
try (InputStream is = contentResolver.openInputStream(uri)) {
Feed feed = feedManager.addFeed(is);
// Update the feed if it was already present
List<Feed> feedList = getList(feeds);
if (feedList == null) feedList = new ArrayList<>();
List<Feed> updated = updateListItems(feedList,
f -> f.equals(feed), f -> feed);
// Add the feed if it wasn't already present
if (updated == null) {
feedList.add(feed);
updated = feedList;
}
feeds.postValue(new LiveResult<>(updated));
importResult.postEvent(new FileImportSuccess());
} catch (IOException | DbException e) {
logException(LOG, WARNING, e);
importResult.postEvent(new FileImportError());
}
});
} }
} }

View File

@@ -1,24 +0,0 @@
package org.briarproject.briar.android.blog;
import org.briarproject.nullsafety.NotNullByDefault;
@NotNullByDefault
abstract class RssImportResult {
static class UrlImportSuccess extends RssImportResult {
}
static class UrlImportError extends RssImportResult {
final String url;
UrlImportError(String url) {
this.url = url;
}
}
static class FileImportSuccess extends RssImportResult {
}
static class FileImportError extends RssImportResult {
}
}

View File

@@ -1,58 +0,0 @@
package org.briarproject.briar.android.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.briar.R;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
import androidx.annotation.Nullable;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class ProgressFragment extends BaseFragment {
public static final String TAG = ProgressFragment.class.getName();
private static final String PROGRESS_MSG = "progressMessage";
public static ProgressFragment newInstance(String message) {
ProgressFragment f = new ProgressFragment();
Bundle args = new Bundle();
args.putString(PROGRESS_MSG, message);
f.setArguments(args);
return f;
}
private String progressMessage;
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = requireArguments();
progressMessage = args.getString(PROGRESS_MSG);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View v = inflater
.inflate(R.layout.fragment_progress, container, false);
TextView msg = v.findViewById(R.id.progressMessage);
msg.setText(progressMessage);
return v;
}
}

View File

@@ -145,7 +145,19 @@ public class MailboxStatusFragment extends Fragment {
@DrawableRes int iconRes; @DrawableRes int iconRes;
String title; String title;
String message = null; String message = null;
if (status.getMailboxCompatibility() < 0) { if (status.hasProblem(System.currentTimeMillis())) {
tintRes = R.color.briar_red_500;
title = getString(R.string.mailbox_status_failure_title);
iconRes = R.drawable.alerts_and_states_error;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else if (status.getAttemptsSinceSuccess() > 0) {
iconRes = R.drawable.ic_help_outline_white;
title = getString(R.string.mailbox_status_problem_title);
tintRes = R.color.briar_orange_500;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else if (status.getMailboxCompatibility() < 0) {
tintRes = R.color.briar_red_500; tintRes = R.color.briar_red_500;
if (status.getMailboxCompatibility() == API_CLIENT_TOO_OLD) { if (status.getMailboxCompatibility() == API_CLIENT_TOO_OLD) {
title = getString(R.string.mailbox_status_app_too_old_title); title = getString(R.string.mailbox_status_app_too_old_title);
@@ -160,18 +172,6 @@ public class MailboxStatusFragment extends Fragment {
iconRes = R.drawable.alerts_and_states_error; iconRes = R.drawable.alerts_and_states_error;
showUnlinkWarning = true; showUnlinkWarning = true;
wizardButton.setVisibility(GONE); wizardButton.setVisibility(GONE);
} else if (status.hasProblem(System.currentTimeMillis())) {
tintRes = R.color.briar_red_500;
title = getString(R.string.mailbox_status_failure_title);
iconRes = R.drawable.alerts_and_states_error;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else if (status.getAttemptsSinceSuccess() > 0) {
iconRes = R.drawable.ic_help_outline_white;
title = getString(R.string.mailbox_status_problem_title);
tintRes = R.color.briar_orange_500;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else { } else {
iconRes = R.drawable.ic_check_circle_outline; iconRes = R.drawable.ic_check_circle_outline;
title = getString(R.string.mailbox_status_connected_title); title = getString(R.string.mailbox_status_connected_title);

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_xlarge">
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="@dimen/hero_square"
android:layout_height="@dimen/hero_square"
android:indeterminate="true"
app:layout_constraintBottom_toTopOf="@+id/progressMessage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.25"
app:layout_constraintVertical_chainStyle="packed"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/progressMessage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_xlarge"
android:gravity="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progress"
tools:text="@string/blogs_rss_feeds_import_progress" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_import_file"
android:icon="@drawable/ic_add_white"
android:title="@string/blogs_rss_feeds_import_title"
app:showAsAction="never"/>
</menu>

View File

@@ -104,7 +104,7 @@
<string name="bt_plugin_status_disabled">Briar е настроен да не използва Bluetooth</string> <string name="bt_plugin_status_disabled">Briar е настроен да не използва Bluetooth</string>
<!--Notifications--> <!--Notifications-->
<string name="reminder_notification_title">Отписани сте от Briar</string> <string name="reminder_notification_title">Отписани сте от Briar</string>
<string name="reminder_notification_text">За да влезете, докоснете</string> <string name="reminder_notification_text">Докоснете за повторно влизане.</string>
<string name="reminder_notification_channel_title">Напомняне за вход в Briar</string> <string name="reminder_notification_channel_title">Напомняне за вход в Briar</string>
<string name="reminder_notification_dismiss">Отказ</string> <string name="reminder_notification_dismiss">Отказ</string>
<string name="ongoing_notification_title">Вписани в Briar</string> <string name="ongoing_notification_title">Вписани в Briar</string>
@@ -235,8 +235,6 @@
<string name="qr_code_invalid">Кодът за QR е недействителен</string> <string name="qr_code_invalid">Кодът за QR е недействителен</string>
<string name="qr_code_too_old_1">Сканираният код за QR е от по-ранно издание на Briar.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string> <string name="qr_code_too_old_1">Сканираният код за QR е от по-ранно издание на Briar.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string>
<string name="qr_code_too_new_1">Сканираният код за QR е от по-ново издание на Briar.\n\nИнсталирайте последното издание и пробвайте отново.</string> <string name="qr_code_too_new_1">Сканираният код за QR е от по-ново издание на Briar.\n\nИнсталирайте последното издание и пробвайте отново.</string>
<string name="mailbox_qr_code_for_contact">Сканираният код за QR е от Briar Пощенска кутия.\n\nАко искате да свържете Пощенска кутия използвайте Настройки &gt; Пощенска кутия от менюто.</string>
<string name="qr_code_format_unknown">Сканираният код за QR не предназначен за добавяне на контакт в Briar.\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>
@@ -482,6 +480,7 @@
<string name="blogs_rss_feeds_import_button">Внасяне</string> <string name="blogs_rss_feeds_import_button">Внасяне</string>
<string name="blogs_rss_feeds_import_hint">рес на емисия</string> <string name="blogs_rss_feeds_import_hint">рес на емисия</string>
<string name="blogs_rss_feeds_import_error">Грешка при внасяне на емисията.</string> <string name="blogs_rss_feeds_import_error">Грешка при внасяне на емисията.</string>
<string name="blogs_rss_feeds_import_exists">Емисията вече е внесена.</string>
<string name="blogs_rss_feeds">Емисии на RSS</string> <string name="blogs_rss_feeds">Емисии на RSS</string>
<string name="blogs_rss_feeds_manage_imported">Внесена:</string> <string name="blogs_rss_feeds_manage_imported">Внесена:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string> <string name="blogs_rss_feeds_manage_author">Автор:</string>
@@ -592,9 +591,7 @@
<string name="mailbox_setup_download_link">Споделяне на препратка за изтегляне</string> <string name="mailbox_setup_download_link">Споделяне на препратка за изтегляне</string>
<string name="mailbox_setup_button_scan">Сканиране на кода за QR на пощенска кутия</string> <string name="mailbox_setup_button_scan">Сканиране на кода за QR на пощенска кутия</string>
<string name="permission_camera_qr_denied_body">Отказахте достъп до камерата, но достъп е необходим за сканиране на кодове за QR.\n\nОбмислете дали да не дадете разрешение.</string> <string name="permission_camera_qr_denied_body">Отказахте достъп до камерата, но достъп е необходим за сканиране на кодове за QR.\n\nОбмислете дали да не дадете разрешение.</string>
<string name="mailbox_setup_connecting">Свързване с Пощенска кутия…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Може да отнеме %1s</string>
<string name="mailbox_setup_already_paired_title">Пощенската кутия е вече свързана</string> <string name="mailbox_setup_already_paired_title">Пощенската кутия е вече свързана</string>
<string name="mailbox_setup_already_paired_description">Прекъснете връзката с пощенската кутия от другото устройство и опитайте отново.</string> <string name="mailbox_setup_already_paired_description">Прекъснете връзката с пощенската кутия от другото устройство и опитайте отново.</string>
<string name="mailbox_setup_io_error_title">Грешка при свързване</string> <string name="mailbox_setup_io_error_title">Грешка при свързване</string>

View File

@@ -489,6 +489,7 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="blogs_rss_feeds_import_button">Subscriu-me</string> <string name="blogs_rss_feeds_import_button">Subscriu-me</string>
<string name="blogs_rss_feeds_import_hint">Escriviu l\'URL del canal de notícies RSS</string> <string name="blogs_rss_feeds_import_hint">Escriviu l\'URL del canal de notícies RSS</string>
<string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en subscriure-us al vostre canal de notícies.</string> <string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en subscriure-us al vostre canal de notícies.</string>
<string name="blogs_rss_feeds_import_exists">Aquest canal ja s\'ha importat.</string>
<string name="blogs_rss_feeds">Canals RSS</string> <string name="blogs_rss_feeds">Canals RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importat:</string> <string name="blogs_rss_feeds_manage_imported">Importat:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -60,8 +60,8 @@
<string name="old_android_expiry_date_reached">Briar wird auf Android 4 nicht mehr unterstützt.\nBitte installiere Briar auf einem neueren Gerät.</string> <string name="old_android_expiry_date_reached">Briar wird auf Android 4 nicht mehr unterstützt.\nBitte installiere Briar auf einem neueren Gerät.</string>
<string name="old_android_delete_account">Du kannst auf die Schaltfläche unten tippen, um dein Konto von diesem Gerät zu löschen.</string> <string name="old_android_delete_account">Du kannst auf die Schaltfläche unten tippen, um dein Konto von diesem Gerät zu löschen.</string>
<string name="delete_account_button">Konto löschen</string> <string name="delete_account_button">Konto löschen</string>
<string name="startup_open_database">Datenbank wird entschlüsselt</string> <string name="startup_open_database">Datenbank wird entschlüsselt...</string>
<string name="startup_migrate_database">Datenbank wird aktualisiert</string> <string name="startup_migrate_database">Datenbank wird aktualisiert...</string>
<string name="startup_compact_database">Datenbank wird komprimiert…</string> <string name="startup_compact_database">Datenbank wird komprimiert…</string>
<!--Navigation Drawer--> <!--Navigation Drawer-->
<string name="nav_drawer_open_description">Navigationsleiste öffnen</string> <string name="nav_drawer_open_description">Navigationsleiste öffnen</string>
@@ -266,9 +266,9 @@
<string name="pending_contact_requests_snackbar">Es gibt ausstehende Kontaktanfragen</string> <string name="pending_contact_requests_snackbar">Es gibt ausstehende Kontaktanfragen</string>
<string name="pending_contact_requests">Ausstehende Kontaktanfragen</string> <string name="pending_contact_requests">Ausstehende Kontaktanfragen</string>
<string name="no_pending_contacts">Keine ausstehenden Kontakte</string> <string name="no_pending_contacts">Keine ausstehenden Kontakte</string>
<string name="waiting_for_contact_to_come_online">Warte auf Online-Aktivität des Kontakts</string> <string name="waiting_for_contact_to_come_online">Warte auf Online-Aktivität des Kontakts ...</string>
<string name="connecting">Verbinde…</string> <string name="connecting">Verbinde…</string>
<string name="adding_contact">Kontakt hinzufügen</string> <string name="adding_contact">Kontakt hinzufügen...</string>
<string name="adding_contact_failed">Hinzufügen von Kontakt ist fehlgeschlagen</string> <string name="adding_contact_failed">Hinzufügen von Kontakt ist fehlgeschlagen</string>
<string name="dialog_title_remove_pending_contact">Entfernung bestätigen</string> <string name="dialog_title_remove_pending_contact">Entfernung bestätigen</string>
<string name="dialog_message_remove_pending_contact">Dieser Kontakt befindet sich noch beim Hinzufügen. Wenn er jetzt entfernt wird, wird das Hinzufügen abgebrochen.</string> <string name="dialog_message_remove_pending_contact">Dieser Kontakt befindet sich noch beim Hinzufügen. Wenn er jetzt entfernt wird, wird das Hinzufügen abgebrochen.</string>
@@ -487,9 +487,8 @@
<string name="blogs_rss_feeds_import">RSS-Feed importieren</string> <string name="blogs_rss_feeds_import">RSS-Feed importieren</string>
<string name="blogs_rss_feeds_import_button">Importieren</string> <string name="blogs_rss_feeds_import_button">Importieren</string>
<string name="blogs_rss_feeds_import_hint">URL des RSS-Feeds eingeben</string> <string name="blogs_rss_feeds_import_hint">URL des RSS-Feeds eingeben</string>
<string name="blogs_rss_feeds_import_progress">RSS-Feed wird importiert…</string>
<string name="blogs_rss_feeds_import_error">Es tut uns Leid! Es gab einen Fehler beim Importieren deines Feeds.</string> <string name="blogs_rss_feeds_import_error">Es tut uns Leid! Es gab einen Fehler beim Importieren deines Feeds.</string>
<string name="blogs_rss_feeds_import_title">Feed aus Datei importieren</string> <string name="blogs_rss_feeds_import_exists">Dieser Feed ist bereits importiert.</string>
<string name="blogs_rss_feeds">RSS-Feeds</string> <string name="blogs_rss_feeds">RSS-Feeds</string>
<string name="blogs_rss_feeds_manage_imported">Importiert:</string> <string name="blogs_rss_feeds_manage_imported">Importiert:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>
@@ -730,7 +729,7 @@
<string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn du dich das nächste Mal bei Briar anmeldest.</string> <string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn du dich das nächste Mal bei Briar anmeldest.</string>
<string name="dev_report_error">Fehler: Senden des Reports fehlgeschlagen</string> <string name="dev_report_error">Fehler: Senden des Reports fehlgeschlagen</string>
<!--Sign Out--> <!--Sign Out-->
<string name="progress_title_logout">Von Briar abmelden</string> <string name="progress_title_logout">Von Briar abmelden...</string>
<!--Screen Filters & Tapjacking--> <!--Screen Filters & Tapjacking-->
<string name="screen_filter_title">Bildschirmüberlagerung erkannt</string> <string name="screen_filter_title">Bildschirmüberlagerung erkannt</string>
<string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nDie folgenden Apps könnten überlagern:\n\n%1$s</string> <string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nDie folgenden Apps könnten überlagern:\n\n%1$s</string>

View File

@@ -495,6 +495,7 @@
<string name="blogs_rss_feeds_import_button">Importar</string> <string name="blogs_rss_feeds_import_button">Importar</string>
<string name="blogs_rss_feeds_import_hint">Introduce la URL del canal RSS</string> <string name="blogs_rss_feeds_import_hint">Introduce la URL del canal RSS</string>
<string name="blogs_rss_feeds_import_error">¡Lo sentimos! Hubo un error importando tu canal.</string> <string name="blogs_rss_feeds_import_error">¡Lo sentimos! Hubo un error importando tu canal.</string>
<string name="blogs_rss_feeds_import_exists">Ese canal ya está importado.</string>
<string name="blogs_rss_feeds">Canales RSS</string> <string name="blogs_rss_feeds">Canales RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importado:</string> <string name="blogs_rss_feeds_manage_imported">Importado:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -510,6 +510,7 @@
<string name="blogs_rss_feeds_import_button">وارد کردن</string> <string name="blogs_rss_feeds_import_button">وارد کردن</string>
<string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string> <string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string>
<string name="blogs_rss_feeds_import_error">متاسفیم! وارد کردن خوراک شما با خطا مواجه شده است.</string> <string name="blogs_rss_feeds_import_error">متاسفیم! وارد کردن خوراک شما با خطا مواجه شده است.</string>
<string name="blogs_rss_feeds_import_exists">این خوراک وارد شده است.</string>
<string name="blogs_rss_feeds">خوراک های RSS</string> <string name="blogs_rss_feeds">خوراک های RSS</string>
<string name="blogs_rss_feeds_manage_imported">وارد شده:</string> <string name="blogs_rss_feeds_manage_imported">وارد شده:</string>
<string name="blogs_rss_feeds_manage_author">نویسنده:</string> <string name="blogs_rss_feeds_manage_author">نویسنده:</string>

View File

@@ -482,6 +482,7 @@
<string name="blogs_rss_feeds_import_button">Importer</string> <string name="blogs_rss_feeds_import_button">Importer</string>
<string name="blogs_rss_feeds_import_hint">Saisir lURL du fil RSS</string> <string name="blogs_rss_feeds_import_hint">Saisir lURL du fil RSS</string>
<string name="blogs_rss_feeds_import_error">Nous sommes désolés! Une erreur est survenue lors de limportation de votre fil.</string> <string name="blogs_rss_feeds_import_error">Nous sommes désolés! Une erreur est survenue lors de limportation de votre fil.</string>
<string name="blogs_rss_feeds_import_exists">Ce fil est déjà importé.</string>
<string name="blogs_rss_feeds">Fils RSS</string> <string name="blogs_rss_feeds">Fils RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importés :</string> <string name="blogs_rss_feeds_manage_imported">Importés :</string>
<string name="blogs_rss_feeds_manage_author">Auteur :</string> <string name="blogs_rss_feeds_manage_author">Auteur :</string>

View File

@@ -466,6 +466,7 @@
<string name="blogs_rss_feeds_import_button">Flytja inn</string> <string name="blogs_rss_feeds_import_button">Flytja inn</string>
<string name="blogs_rss_feeds_import_hint">Settu inn slóðina á RSS-streymið</string> <string name="blogs_rss_feeds_import_hint">Settu inn slóðina á RSS-streymið</string>
<string name="blogs_rss_feeds_import_error">Því miður! Það kom upp villa við að flytja inn streymið.</string> <string name="blogs_rss_feeds_import_error">Því miður! Það kom upp villa við að flytja inn streymið.</string>
<string name="blogs_rss_feeds_import_exists">Þegar er búið að flytja inn þetta streymi.</string>
<string name="blogs_rss_feeds">RSS-fréttastreymi</string> <string name="blogs_rss_feeds">RSS-fréttastreymi</string>
<string name="blogs_rss_feeds_manage_imported">Flutt inn:</string> <string name="blogs_rss_feeds_manage_imported">Flutt inn:</string>
<string name="blogs_rss_feeds_manage_author">Höfundur:</string> <string name="blogs_rss_feeds_manage_author">Höfundur:</string>

View File

@@ -501,9 +501,8 @@
<string name="blogs_rss_feeds_import">Importa RSS Feed</string> <string name="blogs_rss_feeds_import">Importa RSS Feed</string>
<string name="blogs_rss_feeds_import_button">Importa</string> <string name="blogs_rss_feeds_import_button">Importa</string>
<string name="blogs_rss_feeds_import_hint">Inserire l\'URL dell\'RSS feed</string> <string name="blogs_rss_feeds_import_hint">Inserire l\'URL dell\'RSS feed</string>
<string name="blogs_rss_feeds_import_progress">Importazione RSS Feed…</string>
<string name="blogs_rss_feeds_import_error">Ci dispiace! C\'è stato un errore nell\'importazione del tuo feed.</string> <string name="blogs_rss_feeds_import_error">Ci dispiace! C\'è stato un errore nell\'importazione del tuo feed.</string>
<string name="blogs_rss_feeds_import_title">Importa feed da file</string> <string name="blogs_rss_feeds_import_exists">Quel flusso è già importato.</string>
<string name="blogs_rss_feeds">Flussi RSS</string> <string name="blogs_rss_feeds">Flussi RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importato:</string> <string name="blogs_rss_feeds_manage_imported">Importato:</string>
<string name="blogs_rss_feeds_manage_author">Autore:</string> <string name="blogs_rss_feeds_manage_author">Autore:</string>

View File

@@ -1,13 +1,13 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!--Setup--> <!--Setup-->
<string name="setup_title">Briarへようこそ</string> <string name="setup_title">Briar へようこそ</string>
<string name="setup_name_explanation">あなたのニックネームは、常に、あなたが投稿するコンテンツとともに表示されます。プロフィール作成後、編集はできません。</string> <string name="setup_name_explanation">あなたのニックネームは、常に、あなたが投稿するコンテンツとともに表示されます。プロフィール作成後、編集はできません。</string>
<string name="setup_next">次へ</string> <string name="setup_next">次へ</string>
<string name="setup_password_intro">パスワードを選択</string> <string name="setup_password_intro">パスワードを選択</string>
<string name="setup_password_explanation">Briarのアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string> <string name="setup_password_explanation">Briar のアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string>
<string name="dnkm_doze_intro">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。</string> <string name="dnkm_doze_intro">メッセージを受信するために、Briar はバックグラウンドで接続を維持する必要があります。</string>
<string name="dnkm_doze_explanation">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。 Briarが接続を維持できるように、バッテリーの最適化を無効にしてください。</string> <string name="dnkm_doze_explanation">メッセージを受信するために、Briar はバックグラウンドで接続を維持する必要があります。 Briar が接続を維持できるように、バッテリーの最適化を無効にしてください。</string>
<string name="choose_nickname">ニックネームを入力</string> <string name="choose_nickname">ニックネームを入力</string>
<string name="choose_password">パスワードを入力</string> <string name="choose_password">パスワードを入力</string>
<string name="confirm_password">確認のため再度パスワードを入力</string> <string name="confirm_password">確認のため再度パスワードを入力</string>
@@ -17,42 +17,42 @@
<string name="create_account_button">アカウントを作成</string> <string name="create_account_button">アカウントを作成</string>
<string name="more_info">詳細情報</string> <string name="more_info">詳細情報</string>
<string name="don_t_ask_again">次からは尋ねない</string> <string name="don_t_ask_again">次からは尋ねない</string>
<string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面で Briarが保護されていることを確認してください。</string> <string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面で Briar が保護されていることを確認してください。</string>
<string name="dnkm_huawei_protected_button">Briarを保護する</string> <string name="dnkm_huawei_protected_button">Briar を保護する</string>
<string name="dnkm_huawei_protected_help">Briarが保護されたアプリのリストに追加されていないと、Briarはバックグラウンドで実行することができません。</string> <string name="dnkm_huawei_protected_help">Briar が保護されたアプリのリストに追加されていないと、Briar はバックグラウンドで実行することができません。</string>
<string name="dnkm_huawei_app_launch_text">下のボタンをタップして「アプリの起動」画面を開き、Briarが「手動で管理する」に設定されていることを確認してください。</string> <string name="dnkm_huawei_app_launch_text">下のボタンをタップして「アプリの起動」画面を開き、Briar が「手動で管理する」に設定されていることを確認してください。</string>
<string name="dnkm_huawei_app_launch_help">「アプリ起動」画面で Briarを「手動で管理する」に設定していないと、バックグラウンドで動作させることができません。</string> <string name="dnkm_huawei_app_launch_help">「アプリ起動」画面で Briar を「手動で管理する」に設定していないと、バックグラウンドで動作させることができません。</string>
<string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briarを最近のアプリのリストにロックする必要があります。</string> <string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briar を最近のアプリのリストにロックする必要があります。</string>
<string name="dnkm_xiaomi_button">Briarを保護する</string> <string name="dnkm_xiaomi_button">Briar を保護する</string>
<string name="dnkm_xiaomi_help">Briarが最近のアプリのリストにロックされていないと、バックグラウンドで実行することができません。</string> <string name="dnkm_xiaomi_help">Briar が最近のアプリのリストにロックされていないと、バックグラウンドで実行することができません。</string>
<string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリのリスト(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briarの画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. ロックされていない場合は、タップしてロックします。</string> <string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリのリスト(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briar の画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. ロックされていない場合は、タップしてロックします。</string>
<string name="dnkm_warning_dozed_1">Briarはバックグラウンドで実行できませんでした</string> <string name="dnkm_warning_dozed_1">Briarはバックグラウンドで実行することができませんでした</string>
<!--Login--> <!--Login-->
<string name="enter_password">パスワード</string> <string name="enter_password">パスワード</string>
<string name="try_again">パスワードが間違っています。もう一度入力してください。</string> <string name="try_again">パスワードが間違っています。もう一度入力してください。</string>
<string name="dialog_title_cannot_check_password">パスワードを確認できません</string> <string name="dialog_title_cannot_check_password">パスワードを確認できません</string>
<string name="dialog_message_cannot_check_password">Briarがパスワードを確認することができませんでした。この問題を解決するには、端末の再起動を試してください。</string> <string name="dialog_message_cannot_check_password">Briar がパスワードを確認することができませんでした。この問題を解決するには、端末の再起動を試してください。</string>
<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アカウントはクラウド上ではなく、暗号化さた上であなたの端末に保存さています。したがって、Briarはパスワードをリセットできません。アカウントを削除して、はじめからやり直しますか\n\n注意あなたのID、連絡先、メッセージは永久に失われます。</string> <string name="dialog_message_lost_password">Briar アカウントはクラウド上ではなく、暗号化さた上であなたの端末に保存さています。したがって、Briar はパスワードをリセットできません。アカウントを削除して、はじめからやり直しますか?\n\n注意あなたのID、連絡先、メッセージは永久に失われます。</string>
<string name="startup_failed_activity_title">Briarの起動に失敗</string> <string name="startup_failed_activity_title">Briar の起動に失敗しました</string>
<string name="startup_failed_clock_error">お使いの端末の時計が正しくないため、Briarは起動できませんでした。\n\n端末の時計を正しい時刻に設定してから、もう一度試してください。</string> <string name="startup_failed_clock_error">お使いの端末の時計が正しくないため、Briar は起動できませんでした。\n\n端末の時計を正しい時刻に設定してから、もう一度試してください。</string>
<string name="startup_failed_db_error">Briarは、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新しいアカウントを設定してください。</string> <string name="startup_failed_db_error">Briar は、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新しいアカウントを設定してください。</string>
<string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定する必要があります。</string> <string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定する必要があります。</string>
<string name="startup_failed_data_too_new_error">あなたのアカウントは、このアプリの新しいバージョンで作成されたもので、このバージョンでは開くことができません。\n\n最新版にアップグレードしてから、もう一度試してください。</string> <string name="startup_failed_data_too_new_error">あなたのアカウントは、このアプリの新しいバージョンで作成されたもので、このバージョンでは開くことができません。\n\n最新版にアップグレードしてから、もう一度試してください。</string>
<string name="startup_failed_service_error">Briarは要求されたコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string> <string name="startup_failed_service_error">Briar は、必要なコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string>
<plurals name="expiry_warning"> <plurals name="expiry_warning">
<item quantity="other">これは、Briarのテストバージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item> <item quantity="other">これは、Briar のテストバージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item>
</plurals> </plurals>
<plurals name="old_android_expiry_warning"> <plurals name="old_android_expiry_warning">
<item quantity="other">Android 4はサポートされなくなりました。Briarは(%d日後に)%s上での動作を停止します。新しい端末に Briarをインストールして、新しいアカウントを作成してください。</item> <item quantity="other">Android 4はサポートされなくなりました。Briar は(%d日後に)%s上での動作を停止します。新しい端末に Briar をインストールして、新しいアカウントを作成してください。</item>
</plurals> </plurals>
<string name="expiry_date_reached">このソフトウェアの有効期限が切れました。テストに参加してくださりありがとうございます!</string> <string name="expiry_date_reached">このソフトウェアの有効期限が切れました。テストに参加してくださりありがとうございます!</string>
<string name="download_briar">Briarの使用を続けるには、最新リリースをダウンロードしてください。</string> <string name="download_briar">Briarの使用を続けるには、最新リリースをダウンロードしてください。</string>
<string name="create_new_account">新しいアカウントを作成する必要があります。同じニックネームも使用できます。</string> <string name="create_new_account">新しいアカウントを作成する必要があります。同じニックネームも使用できます。</string>
<string name="download_briar_button">最新リリースをダウンロード</string> <string name="download_briar_button">最新リリースをダウンロード</string>
<string name="old_android_expiry_date_reached">BriarAndroid 4では動作しなくなりました。\n新しい端末にBriarをインストールしてください。</string> <string name="old_android_expiry_date_reached">BriarAndroid 4 では動作しなくなりました。\n新しい端末にBriarをインストールしてください。</string>
<string name="old_android_delete_account">下のボタンをタップして、この端末からあなたのアカウントを削除できます。</string> <string name="old_android_delete_account">下のボタンをタップして、この端末からあなたのアカウントを削除できます。</string>
<string name="delete_account_button">アカウントを削除</string> <string name="delete_account_button">アカウントを削除</string>
<string name="startup_open_database">データベースの復号化中…</string> <string name="startup_open_database">データベースの復号化中…</string>
@@ -69,36 +69,36 @@
<string name="lock_button">アプリをロック</string> <string name="lock_button">アプリをロック</string>
<string name="settings_button">設定</string> <string name="settings_button">設定</string>
<string name="sign_out_button">サインアウト</string> <string name="sign_out_button">サインアウト</string>
<string name="transports_onboarding_text">ここにタップすると、Briarがあなたの連絡先に接続する方法を制御できます。</string> <string name="transports_onboarding_text">ここにタップすると、Briar があなたの連絡先に接続する方法を制御できます。</string>
<!--Transports: Tor--> <!--Transports: Tor-->
<string name="transport_tor">インターネット</string> <string name="transport_tor">インターネット</string>
<string name="tor_device_status_online_wifi">電話機はWi-Fiでインターネットにアクセスできます</string> <string name="tor_device_status_online_wifi">電話機はWi-Fiでインターネットにアクセスできます</string>
<string name="tor_device_status_online_mobile">電話機はモバイル データでインターネットにアクセスできます</string> <string name="tor_device_status_online_mobile">電話機はモバイル データでインターネットにアクセスできます</string>
<string name="tor_device_status_offline">電話機がインターネットに接続できません</string> <string name="tor_device_status_offline">電話機がインターネットに接続できません</string>
<string name="tor_plugin_status_enabling">Briarはインターネットに接続中です…</string> <string name="tor_plugin_status_enabling">Briar はインターネットに接続中です…</string>
<string name="tor_plugin_status_active">Briarはインターネットに接続されました</string> <string name="tor_plugin_status_active">Briar はインターネットに接続されました</string>
<string name="tor_plugin_status_inactive">Briarはインターネットに接続できません</string> <string name="tor_plugin_status_inactive">Briar はインターネットに接続できません</string>
<string name="tor_plugin_status_disabled">Briarはインターネットを使用しないように設定されています</string> <string name="tor_plugin_status_disabled">Briar はインターネットを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_mobile_data">Briarはモバイルデータを使用しないように設定されています</string> <string name="tor_plugin_status_disabled_mobile_data">Briar はモバイルデータを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_battery">Briarはバッテリー駆動時にインターネットを使用しないように設定されています</string> <string name="tor_plugin_status_disabled_battery">Briar はバッテリー駆動時にインターネットを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_country_blocked">Briarはこの国でインターネットを使わないように設定されています</string> <string name="tor_plugin_status_disabled_country_blocked">Briar はこの国でインターネットを使わないように設定されています</string>
<!--Transports: Wi-Fi--> <!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string> <string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">同じ Wi-Fi ネットワーク</string> <string name="transport_lan_long">同じ Wi-Fi ネットワーク</string>
<string name="lan_device_status_on">電話機は Wi-Fi に接続されました</string> <string name="lan_device_status_on">電話機は Wi-Fi に接続されました</string>
<string name="lan_device_status_off">電話機はWi-Fiに接続されていません</string> <string name="lan_device_status_off">電話機はWi-Fiに接続されていません</string>
<string name="lan_plugin_status_enabling">BriarWi-Fiネットワークに接続中です…</string> <string name="lan_plugin_status_enabling">BriarWi-Fi ネットワークに接続中です…</string>
<string name="lan_plugin_status_active">BriarWi-Fiネットワークに接続されました</string> <string name="lan_plugin_status_active">BriarWi-Fi ネットワークに接続されました</string>
<string name="lan_plugin_status_inactive">BriarWi-Fiネットワークに接続できません</string> <string name="lan_plugin_status_inactive">BriarWi-Fi ネットワークに接続できません</string>
<string name="lan_plugin_status_disabled">BriarWi-Fiネットワークを使用しないように設定されています</string> <string name="lan_plugin_status_disabled">BriarWi-Fi ネットワークを使用しないように設定されています</string>
<!--Transports: Bluetooth--> <!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string> <string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">携帯電話の Bluetooth はオンになっています</string> <string name="bt_device_status_on">携帯電話の Bluetooth はオンになっています</string>
<string name="bt_device_status_off">携帯電話の Bluetooth はオフにされました</string> <string name="bt_device_status_off">携帯電話の Bluetooth はオフにされました</string>
<string name="bt_plugin_status_enabling">BriarBluetoothに接続中です…</string> <string name="bt_plugin_status_enabling">BriarBluetooth に接続中です…</string>
<string name="bt_plugin_status_active">BriarBluetoothに接続しました</string> <string name="bt_plugin_status_active">BriarBluetooth に接続しました</string>
<string name="bt_plugin_status_inactive">BriarBluetoothに接続できません</string> <string name="bt_plugin_status_inactive">BriarBluetooth に接続できません</string>
<string name="bt_plugin_status_disabled">BriarBluetoothを使用しないように設定されています</string> <string name="bt_plugin_status_disabled">BriarBluetooth を使用しないように設定されています</string>
<!--Notifications--> <!--Notifications-->
<string name="reminder_notification_title">Briarからサインアウト</string> <string name="reminder_notification_title">Briarからサインアウト</string>
<string name="reminder_notification_text">タップして再ログインします。</string> <string name="reminder_notification_text">タップして再ログインします。</string>
@@ -323,7 +323,6 @@
<string name="connect_via_bluetooth_intro">Bluetooth接続が自動的に行われない場合は、この画面を使って手動で接続することができます。\n\nこの機能を利用するには、あなたの連絡先が近くにある必要があります。\n\nあなたと連絡先が同時に\"開始\"を押してください。</string> <string name="connect_via_bluetooth_intro">Bluetooth接続が自動的に行われない場合は、この画面を使って手動で接続することができます。\n\nこの機能を利用するには、あなたの連絡先が近くにある必要があります。\n\nあなたと連絡先が同時に\"開始\"を押してください。</string>
<string name="connect_via_bluetooth_already_discovering">既にBluetooth経由での接続を試行中です。すぐに再試行してください。</string> <string name="connect_via_bluetooth_already_discovering">既にBluetooth経由での接続を試行中です。すぐに再試行してください。</string>
<string name="connect_via_bluetooth_no_location_permission">位置情報の権限なくして続行不可能</string> <string name="connect_via_bluetooth_no_location_permission">位置情報の権限なくして続行不可能</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">付近の端末の権限なくして続行不可能</string>
<string name="connect_via_bluetooth_start">Bluetooth経由で接続中…</string> <string name="connect_via_bluetooth_start">Bluetooth経由で接続中…</string>
<string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string> <string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string>
<string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string> <string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string>
@@ -349,9 +348,9 @@
<string name="groups_member_created">%sがグループを作成しました</string> <string name="groups_member_created">%sがグループを作成しました</string>
<string name="groups_member_joined_you">グループに参加しました</string> <string name="groups_member_joined_you">グループに参加しました</string>
<string name="groups_member_joined">%sがグループに参加しました</string> <string name="groups_member_joined">%sがグループに参加しました</string>
<string name="groups_leave">グループを脱退</string> <string name="groups_leave">グループをやめる</string>
<string name="groups_leave_dialog_title">グループをやめる確認</string> <string name="groups_leave_dialog_title">グループをやめる確認</string>
<string name="groups_leave_dialog_message">このグループを脱退してもよろしいですか?</string> <string name="groups_leave_dialog_message">このグループをやめてもよろしいですか?</string>
<string name="groups_dissolve">グループを削除</string> <string name="groups_dissolve">グループを削除</string>
<string name="groups_dissolve_dialog_title">グループの削除の確認</string> <string name="groups_dissolve_dialog_title">グループの削除の確認</string>
<string name="groups_dissolve_dialog_message">このグループを削除してもよろしいですか?\n\nグループを削除すると、他のすべてのメンバーは会話を続けることができなくなり、最新のメッセージは受信できなくなります。</string> <string name="groups_dissolve_dialog_message">このグループを削除してもよろしいですか?\n\nグループを削除すると、他のすべてのメンバーは会話を続けることができなくなり、最新のメッセージは受信できなくなります。</string>
@@ -395,10 +394,10 @@
<string name="forum_new_message_hint">新しい投稿</string> <string name="forum_new_message_hint">新しい投稿</string>
<string name="forum_message_reply_hint">新しい返信</string> <string name="forum_message_reply_hint">新しい返信</string>
<string name="btn_reply">返信</string> <string name="btn_reply">返信</string>
<string name="forum_leave">フォーラムを脱退</string> <string name="forum_leave">フォーラムをやめる</string>
<string name="dialog_title_leave_forum">フォーラムをやめる確認</string> <string name="dialog_title_leave_forum">フォーラムをやめる確認</string>
<string name="dialog_message_leave_forum">このフォーラムを脱退してもよろしいですか?\n\nこのフォーラムで共有した連絡先は更新の受信を停止します。</string> <string name="dialog_message_leave_forum">このフォーラムをやめてもよろしいですか?\n\nこのフォーラムで共有した連絡先は更新の受信を停止します。</string>
<string name="dialog_button_leave">脱退</string> <string name="dialog_button_leave">脱退する</string>
<string name="forum_left_toast">フォーラムをやめました</string> <string name="forum_left_toast">フォーラムをやめました</string>
<!--Forum Sharing--> <!--Forum Sharing-->
<string name="forum_share_button">フォーラムを共有</string> <string name="forum_share_button">フォーラムを共有</string>
@@ -417,10 +416,6 @@
<string name="forum_declined_toast">招待を辞退しました</string> <string name="forum_declined_toast">招待を辞退しました</string>
<string name="shared_by_format">%sによって共有されました。</string> <string name="shared_by_format">%sによって共有されました。</string>
<string name="forum_invitation_already_sharing">既に共有しています</string> <string name="forum_invitation_already_sharing">既に共有しています</string>
<string name="forum_invitation_already_invited">招待は既に送信しました</string>
<string name="forum_invitation_invite_received">招待は既に受信されました</string>
<string name="forum_invitation_not_supported">この連絡先によってサポートされていません</string>
<string name="forum_invitation_error">エラー。これはバグか、そうでなければ、あなたの誤りです</string>
<string name="forum_invitation_response_accepted_sent">%sからのフォーラムへの招待を受け入れました。</string> <string name="forum_invitation_response_accepted_sent">%sからのフォーラムへの招待を受け入れました。</string>
<string name="forum_invitation_response_declined_sent">%sからのフォーラムへの招待を辞退しました。</string> <string name="forum_invitation_response_declined_sent">%sからのフォーラムへの招待を辞退しました。</string>
<string name="forum_invitation_response_declined_auto">%sからのフォーラムへの招待は自動的に辞退されました。</string> <string name="forum_invitation_response_declined_auto">%sからのフォーラムへの招待は自動的に辞退されました。</string>
@@ -470,9 +465,8 @@
<string name="blogs_rss_feeds_import">RSSフィードをインポート</string> <string name="blogs_rss_feeds_import">RSSフィードをインポート</string>
<string name="blogs_rss_feeds_import_button">インポート</string> <string name="blogs_rss_feeds_import_button">インポート</string>
<string name="blogs_rss_feeds_import_hint">RSSフィードのURLを入力してください</string> <string name="blogs_rss_feeds_import_hint">RSSフィードのURLを入力してください</string>
<string name="blogs_rss_feeds_import_progress">RSSフィードをインポート中…</string>
<string name="blogs_rss_feeds_import_error">申し訳ありません! フィードのインポート中にエラーが発生しました。</string> <string name="blogs_rss_feeds_import_error">申し訳ありません! フィードのインポート中にエラーが発生しました。</string>
<string name="blogs_rss_feeds_import_title">ファイルからフィードインポート</string> <string name="blogs_rss_feeds_import_exists">そのフィードは既にインポートされています。</string>
<string name="blogs_rss_feeds">RSSフィード</string> <string name="blogs_rss_feeds">RSSフィード</string>
<string name="blogs_rss_feeds_manage_imported">インポート済み:</string> <string name="blogs_rss_feeds_manage_imported">インポート済み:</string>
<string name="blogs_rss_feeds_manage_author">著者:</string> <string name="blogs_rss_feeds_manage_author">著者:</string>
@@ -579,7 +573,7 @@
<string name="mailbox_setup_title">メールボックスのセットアップ</string> <string name="mailbox_setup_title">メールボックスのセットアップ</string>
<string name="mailbox_setup_intro">メールボックスはあなたがオフラインの間、連絡先があなたにメッセージを送信することを有効にします。メールボックスはあなたがオンラインになるまで、メッセージを受信し保管します。\n <string name="mailbox_setup_intro">メールボックスはあなたがオフラインの間、連絡先があなたにメッセージを送信することを有効にします。メールボックスはあなたがオンラインになるまで、メッセージを受信し保管します。\n
\n予備端末上にBriarのメールボックスアプリをインストールできます。それを電源とWi-Fiに接続し、常時オンラインにしてください。</string> \n予備端末上にBriarのメールボックスアプリをインストールできます。それを電源とWi-Fiに接続し、常時オンラインにしてください。</string>
<string name="mailbox_setup_download">最初に、Google PlayまたはBriarをダウンロードしたどこかで\"BriarMailbox\"を検索して、他の端末上にメールボックスアプリをインストールします。\n <string name="mailbox_setup_download">最初に、Google PlayまたはBriarをダウンロードしたどこかで\"Briar Mailbox\"を検索して、他の端末上にメールボックスアプリをインストールします。\n
\nそして、メールボックスアプリによって表示されるQRコードを読み取って、Briarとあなたのメールボックス結びつけます。</string> \nそして、メールボックスアプリによって表示されるQRコードを読み取って、Briarとあなたのメールボックス結びつけます。</string>
<string name="mailbox_setup_download_link">ダウンロードリンクを共有</string> <string name="mailbox_setup_download_link">ダウンロードリンクを共有</string>
<string name="mailbox_setup_button_scan">メールボックスのQRコードを読み取る</string> <string name="mailbox_setup_button_scan">メールボックスのQRコードを読み取る</string>
@@ -591,15 +585,15 @@
<string name="mailbox_qr_code_too_new">読み取ったQRコードは、新しいバージョンのBriarメールボックスから生じました。\n\nBriarを最新版にアップグレードしてから、もう一度お試しください。</string> <string name="mailbox_qr_code_too_new">読み取ったQRコードは、新しいバージョンのBriarメールボックスから生じました。\n\nBriarを最新版にアップグレードしてから、もう一度お試しください。</string>
<string name="contact_qr_code_for_mailbox">読み取ったQRコードは、Briarの連絡先を追加するためのものです。\n\n連絡先を追加したいならば、連絡先一覧に行き、+アイコンをタップしてください。</string> <string name="contact_qr_code_for_mailbox">読み取ったQRコードは、Briarの連絡先を追加するためのものです。\n\n連絡先を追加したいならば、連絡先一覧に行き、+アイコンをタップしてください。</string>
<string name="mailbox_setup_qr_code_wrong_description">読み取ったQRコードは、Briarメールボックスから生じたものではありません。メールボックス端末上のBriarメールボックスアプリを開き、提示されたQRコードを読み取ってください。</string> <string name="mailbox_setup_qr_code_wrong_description">読み取ったQRコードは、Briarメールボックスから生じたものではありません。メールボックス端末上のBriarメールボックスアプリを開き、提示されたQRコードを読み取ってください。</string>
<string name="mailbox_setup_already_paired_title">メールボックスは既にリンクされています</string> <string name="mailbox_setup_already_paired_title">メールボックスは既に結びつけられています</string>
<string name="mailbox_setup_already_paired_description">あなたの端末上のメールボックスのリンクを解き、再試行してください。</string> <string name="mailbox_setup_already_paired_description">あなたの端末上のメールボックスの結びつけを解き、再試行してください。</string>
<string name="mailbox_setup_io_error_title">接続できません</string> <string name="mailbox_setup_io_error_title">接続できません</string>
<string name="mailbox_setup_io_error_description">双方の端末がインターネットに接続されていることを確かにして、再試行してください。</string> <string name="mailbox_setup_io_error_description">双方の端末がインターネットに接続されていることを確かにして、再試行してください。</string>
<string name="mailbox_setup_assertion_error_title">メールボックスのエラー</string> <string name="mailbox_setup_assertion_error_title">メールボックスのエラー</string>
<string name="mailbox_setup_assertion_error_description">もし問題が続くのであれば、Briarアプリ経由で匿名データ付きのフィードバックを送信してください。</string> <string name="mailbox_setup_assertion_error_description">もし問題が続くのであれば、Briarアプリ経由で匿名データ付きのフィードバックを送信してください。</string>
<string name="mailbox_setup_camera_error_description">カメラにアクセスできません。端末を再起動してから、もう一度試してみてください。</string> <string name="mailbox_setup_camera_error_description">カメラにアクセスできません。端末を再起動してから、もう一度試してみてください。</string>
<string name="mailbox_setup_paired_title">接続済み</string> <string name="mailbox_setup_paired_title">接続済み</string>
<string name="mailbox_setup_paired_description">あなたのメールボックスはBriarとのリンクに成功しています。\n <string name="mailbox_setup_paired_description">あなたのメールボックスはBriarとの結びつけられるのに成功しています。\n
メールボックスを電源とW-Fiに接続して、常時オンラインにしてください。</string> メールボックスを電源とW-Fiに接続して、常時オンラインにしてください。</string>
<string name="tor_offline_title">オフライン</string> <string name="tor_offline_title">オフライン</string>
<string name="tor_offline_description">この端末がオンラインかつインターネットへの接続が許可されていること確かにしてください。\n <string name="tor_offline_description">この端末がオンラインかつインターネットへの接続が許可されていること確かにしてください。\n
@@ -639,7 +633,7 @@
<string name="mailbox_error_wizard_answer1_1">メールボックスの設定方法が表示される</string> <string name="mailbox_error_wizard_answer1_1">メールボックスの設定方法が表示される</string>
<string name="mailbox_error_wizard_answer1_2">QRコードが表示される</string> <string name="mailbox_error_wizard_answer1_2">QRコードが表示される</string>
<string name="mailbox_error_wizard_answer1_3">「メールボックスは実行中」と表示される</string> <string name="mailbox_error_wizard_answer1_3">「メールボックスは実行中」と表示される</string>
<string name="mailbox_error_wizard_answer1_4">端末がオフライン」と表示されます</string> <string name="mailbox_error_wizard_answer1_4">デバイスがオフライン」と表示されます</string>
<string name="mailbox_error_wizard_info1_1_1">以下のボタンでメールボックスのリンクを解除し、メールボックスの端末の指示に従って再度リンクしてください。</string> <string name="mailbox_error_wizard_info1_1_1">以下のボタンでメールボックスのリンクを解除し、メールボックスの端末の指示に従って再度リンクしてください。</string>
<string name="mailbox_error_wizard_info_1_1_2">以下のボタンでメールボックスのリンクを解除し、QRコードを読み取って再度リンクしてください。</string> <string name="mailbox_error_wizard_info_1_1_2">以下のボタンでメールボックスのリンクを解除し、QRコードを読み取って再度リンクしてください。</string>
<string name="mailbox_error_wizard_info1_1_3">以下のボタンを使用して、Briarとメールボックスの間での接続を確認してください。\n\n <string name="mailbox_error_wizard_info1_1_3">以下のボタンを使用して、Briarとメールボックスの間での接続を確認してください。\n\n
@@ -651,7 +645,7 @@
<string name="mailbox_error_wizard_info3">以下のボタンを使用してメールボックスをリンク解除してください。\n\n古いメールボックスをリンク解除した後、いつでも新しいメールボックスをセットアップできます。</string> <string name="mailbox_error_wizard_info3">以下のボタンを使用してメールボックスをリンク解除してください。\n\n古いメールボックスをリンク解除した後、いつでも新しいメールボックスをセットアップできます。</string>
<!--About--> <!--About-->
<string name="about_title">Tor Project について</string> <string name="about_title">Tor Project について</string>
<string name="briar_version">Briarバージョン: %s</string> <string name="briar_version">Briar バージョン: %s</string>
<string name="tor_version">Tor バージョン: %s</string> <string name="tor_version">Tor バージョン: %s</string>
<string name="links">リンク</string> <string name="links">リンク</string>
<string name="briar_website">\u2022 <a href="">ウェブサイト</a></string> <string name="briar_website">\u2022 <a href="">ウェブサイト</a></string>
@@ -783,7 +777,7 @@
<string name="hotspot_manual_site_address">アドレスURL</string> <string name="hotspot_manual_site_address">アドレスURL</string>
<string name="hotspot_qr_site">あなたの電話機はWi-Fiホットスポットを提供しています。ホットスポットに接続された人は、このQRコードを読み取って、Briarをダウンロードできます。</string> <string name="hotspot_qr_site">あなたの電話機はWi-Fiホットスポットを提供しています。ホットスポットに接続された人は、このQRコードを読み取って、Briarをダウンロードできます。</string>
<!--e.g. Download Briar 1.2.20--> <!--e.g. Download Briar 1.2.20-->
<string name="website_download_title_1">Briar%sをダウンロード</string> <string name="website_download_title_1">Briar %sをダウンロード</string>
<string name="website_download_intro_1">近くの誰かが、あなたとBriarを共有しました。</string> <string name="website_download_intro_1">近くの誰かが、あなたとBriarを共有しました。</string>
<string name="website_download_button">Briarをダウンロード</string> <string name="website_download_button">Briarをダウンロード</string>
<string name="website_download_outro">ダウンロードが完了した後に、ダウンロードしたファイルを開いて、インストールしてください。</string> <string name="website_download_outro">ダウンロードが完了した後に、ダウンロードしたファイルを開いて、インストールしてください。</string>

View File

@@ -477,6 +477,7 @@
<string name="blogs_rss_feeds_import_button">იმპორტი</string> <string name="blogs_rss_feeds_import_button">იმპორტი</string>
<string name="blogs_rss_feeds_import_hint">შეიყვანეთ RSS არხის URL</string> <string name="blogs_rss_feeds_import_hint">შეიყვანეთ RSS არხის URL</string>
<string name="blogs_rss_feeds_import_error">ვწუხვართ! არხის იმპორტირებისას შეცდომა წარმოიშვა.</string> <string name="blogs_rss_feeds_import_error">ვწუხვართ! არხის იმპორტირებისას შეცდომა წარმოიშვა.</string>
<string name="blogs_rss_feeds_import_exists">არხი უკვე იმპორტირებულია.</string>
<string name="blogs_rss_feeds">RSS არხები</string> <string name="blogs_rss_feeds">RSS არხები</string>
<string name="blogs_rss_feeds_manage_imported">იმპორტირებული:</string> <string name="blogs_rss_feeds_manage_imported">იმპორტირებული:</string>
<string name="blogs_rss_feeds_manage_author">ავტორი:</string> <string name="blogs_rss_feeds_manage_author">ავტორი:</string>

View File

@@ -313,8 +313,6 @@
<string name="duplicate_link_dialog_text_3">%1$s ir %2$s išsiuntė jums tą pačią nuorodą.\n\nGali būti, kad vienas iš šių asmenų bando sužinoti kas yra jūsų adresatų sąraše.\n\nNesakykite šiems asmenims, kad gavote tokią pačią nuorodą iš kito asmens.</string> <string name="duplicate_link_dialog_text_3">%1$s ir %2$s išsiuntė jums tą pačią nuorodą.\n\nGali būti, kad vienas iš šių asmenų bando sužinoti kas yra jūsų adresatų sąraše.\n\nNesakykite šiems asmenims, kad gavote tokią pačią nuorodą iš kito asmens.</string>
<string name="pending_contact_updated_toast">Laukiantis adresatas atnaujintas</string> <string name="pending_contact_updated_toast">Laukiantis adresatas atnaujintas</string>
<!--Peer trust levels--> <!--Peer trust levels-->
<string name="peer_trust_level_ourselves"></string>
<string name="peer_trust_level_stranger">Nepažįstamasis</string>
<!--Introductions--> <!--Introductions-->
<string name="introduction_onboarding_title">Supažindinkite savo adresatus</string> <string name="introduction_onboarding_title">Supažindinkite savo adresatus</string>
<string name="introduction_menu_item">Supažindinti</string> <string name="introduction_menu_item">Supažindinti</string>
@@ -444,9 +442,6 @@
<string name="forum_declined_toast">Pakvietimas atmestas</string> <string name="forum_declined_toast">Pakvietimas atmestas</string>
<string name="shared_by_format">Bendrina %s</string> <string name="shared_by_format">Bendrina %s</string>
<string name="forum_invitation_already_sharing">Jau bendrinama</string> <string name="forum_invitation_already_sharing">Jau bendrinama</string>
<string name="forum_invitation_already_invited">Pakvietimas jau išsiųstas</string>
<string name="forum_invitation_invite_received">Pakvietimas jau gautas</string>
<string name="forum_invitation_error">Klaida. Tai yra triktis ir ne jūsų kaltė</string>
<string name="forum_invitation_response_accepted_sent">Jūs priėmėte pakvietimą į forumą iš %s.</string> <string name="forum_invitation_response_accepted_sent">Jūs priėmėte pakvietimą į forumą iš %s.</string>
<string name="forum_invitation_response_declined_sent">Jūs atmetėte pakvietimą į forumą iš %s.</string> <string name="forum_invitation_response_declined_sent">Jūs atmetėte pakvietimą į forumą iš %s.</string>
<string name="forum_invitation_response_declined_auto">Pakvietimas į forumą nuo %s buvo automatiškai atmestas.</string> <string name="forum_invitation_response_declined_auto">Pakvietimas į forumą nuo %s buvo automatiškai atmestas.</string>
@@ -499,9 +494,8 @@
<string name="blogs_rss_feeds_import">Importuoti RSS kanalą</string> <string name="blogs_rss_feeds_import">Importuoti RSS kanalą</string>
<string name="blogs_rss_feeds_import_button">Importuoti</string> <string name="blogs_rss_feeds_import_button">Importuoti</string>
<string name="blogs_rss_feeds_import_hint">Įveskite RSS kanalo URL</string> <string name="blogs_rss_feeds_import_hint">Įveskite RSS kanalo URL</string>
<string name="blogs_rss_feeds_import_progress">Importuojamas RSS kanalas…</string>
<string name="blogs_rss_feeds_import_error">Atleiskite! Importuojant jūsų kanalą, įvyko klaida.</string> <string name="blogs_rss_feeds_import_error">Atleiskite! Importuojant jūsų kanalą, įvyko klaida.</string>
<string name="blogs_rss_feeds_import_title">Importuoti kanalą iš failo</string> <string name="blogs_rss_feeds_import_exists">Tas kanalas jau yra importuotas.</string>
<string name="blogs_rss_feeds">RSS kanalai</string> <string name="blogs_rss_feeds">RSS kanalai</string>
<string name="blogs_rss_feeds_manage_imported">Importuota:</string> <string name="blogs_rss_feeds_manage_imported">Importuota:</string>
<string name="blogs_rss_feeds_manage_author">Autorius:</string> <string name="blogs_rss_feeds_manage_author">Autorius:</string>
@@ -611,7 +605,6 @@
<string name="mailbox_setup_download_link">Bendrinti atsisiuntimo nuorodą</string> <string name="mailbox_setup_download_link">Bendrinti atsisiuntimo nuorodą</string>
<string name="mailbox_setup_button_scan">Skenuoti pašto dėžutės QR kodą</string> <string name="mailbox_setup_button_scan">Skenuoti pašto dėžutės QR kodą</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Tai gali užtrukti iki %1s</string>
<string name="mailbox_setup_already_paired_title">Pašto dėžutė jau susieta</string> <string name="mailbox_setup_already_paired_title">Pašto dėžutė jau susieta</string>
<string name="mailbox_setup_io_error_title">Nepavyko prisijungti</string> <string name="mailbox_setup_io_error_title">Nepavyko prisijungti</string>
<string name="mailbox_setup_io_error_description">Įsitikinkite, kad abu įrenginiai yra prisijungę prie interneto ir bandykite dar kartą.</string> <string name="mailbox_setup_io_error_description">Įsitikinkite, kad abu įrenginiai yra prisijungę prie interneto ir bandykite dar kartą.</string>
@@ -648,7 +641,6 @@
<string name="briar_changelog">\u2022 <a href="">Keitinių žurnalas</a></string> <string name="briar_changelog">\u2022 <a href="">Keitinių žurnalas</a></string>
<string name="briar_privacy_policy">\u2022 <a href="">Privatumo politika</a></string> <string name="briar_privacy_policy">\u2022 <a href="">Privatumo politika</a></string>
<!--Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry")--> <!--Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry")-->
<string name="translator_thanks">Dėkojame talkininkams iš Localization Lab, ypač Moo už vertimą į lietuvių kalbą</string>
<!--Conversation Settings--> <!--Conversation Settings-->
<string name="disappearing_messages_title">Išnykstančios žinutės</string> <string name="disappearing_messages_title">Išnykstančios žinutės</string>
<string name="disappearing_messages_explanation_long">Įjungus šį nustatymą, naujos žinutės <string name="disappearing_messages_explanation_long">Įjungus šį nustatymą, naujos žinutės

View File

@@ -460,6 +460,7 @@
<string name="blogs_rss_feeds_import_button">တင်သွင်းမည်</string> <string name="blogs_rss_feeds_import_button">တင်သွင်းမည်</string>
<string name="blogs_rss_feeds_import_hint">RSS သတင်းပို့စ်အလွှာ၏ URL ရိုက်ထည့်ပေးပါ</string> <string name="blogs_rss_feeds_import_hint">RSS သတင်းပို့စ်အလွှာ၏ URL ရိုက်ထည့်ပေးပါ</string>
<string name="blogs_rss_feeds_import_error">ဝမ်းနည်းပါသည်! သင့် သတင်းပို့စ်အလွှာအား တင်သွင်းရာတွင် ပျက်ကွက်မှု ဖြစ်ခဲ့ပါသည်။</string> <string name="blogs_rss_feeds_import_error">ဝမ်းနည်းပါသည်! သင့် သတင်းပို့စ်အလွှာအား တင်သွင်းရာတွင် ပျက်ကွက်မှု ဖြစ်ခဲ့ပါသည်။</string>
<string name="blogs_rss_feeds_import_exists">Feed ကို တင်ပို့ပြီး ဖြစ်သည်။</string>
<string name="blogs_rss_feeds">RSS သတင်းလွှာများ</string> <string name="blogs_rss_feeds">RSS သတင်းလွှာများ</string>
<string name="blogs_rss_feeds_manage_imported">တင်သွင်းထားသော</string> <string name="blogs_rss_feeds_manage_imported">တင်သွင်းထားသော</string>
<string name="blogs_rss_feeds_manage_author">စာရေးဆရာ -</string> <string name="blogs_rss_feeds_manage_author">စာရေးဆရာ -</string>

View File

@@ -477,6 +477,7 @@
<string name="blogs_rss_feeds_import_button">Importer</string> <string name="blogs_rss_feeds_import_button">Importer</string>
<string name="blogs_rss_feeds_import_hint">Skriv inn nettadresse for RSS-strøm</string> <string name="blogs_rss_feeds_import_hint">Skriv inn nettadresse for RSS-strøm</string>
<string name="blogs_rss_feeds_import_error">Vi beklager! Feil under importering av strøm.</string> <string name="blogs_rss_feeds_import_error">Vi beklager! Feil under importering av strøm.</string>
<string name="blogs_rss_feeds_import_exists">Den feed\'en er importert allerede</string>
<string name="blogs_rss_feeds">RSS-feed\'er</string> <string name="blogs_rss_feeds">RSS-feed\'er</string>
<string name="blogs_rss_feeds_manage_imported">Importert:</string> <string name="blogs_rss_feeds_manage_imported">Importert:</string>
<string name="blogs_rss_feeds_manage_author">Forfatter:</string> <string name="blogs_rss_feeds_manage_author">Forfatter:</string>

View File

@@ -244,7 +244,6 @@
<string name="menu_contact">Kontakt</string> <string name="menu_contact">Kontakt</string>
<!--Adding Contacts--> <!--Adding Contacts-->
<string name="add_contact_title">Dodaj kontakt w pobliżu</string> <string name="add_contact_title">Dodaj kontakt w pobliżu</string>
<string name="add_contact_error_two_way">Czy oboje skanowaliście nawzajem swoje kody QR?</string>
<string name="face_to_face">Musisz spotkać się z osobą którą chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek udawanie Ciebie lub czytanie Twoich wiadomości w przyszłości.</string> <string name="face_to_face">Musisz spotkać się z osobą którą chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek udawanie Ciebie lub czytanie Twoich wiadomości w przyszłości.</string>
<string name="continue_button">Kontynuuj</string> <string name="continue_button">Kontynuuj</string>
<string name="try_again_button">Spróbuj ponownie</string> <string name="try_again_button">Spróbuj ponownie</string>
@@ -260,7 +259,6 @@
<string name="authenticating_with_device">Autoryzowanie z urządzeniem\u2026</string> <string name="authenticating_with_device">Autoryzowanie z urządzeniem\u2026</string>
<string name="connection_error_title">Nie udało się połączyć z kontaktem</string> <string name="connection_error_title">Nie udało się połączyć z kontaktem</string>
<string name="connection_error_feedback">Jeśli problem będzie występować dalej, proszę <a href="feedback">wysłać opinię</a> aby pomóc nam ulepszyć aplikację.</string> <string name="connection_error_feedback">Jeśli problem będzie występować dalej, proszę <a href="feedback">wysłać opinię</a> aby pomóc nam ulepszyć aplikację.</string>
<string name="info_both_must_scan">Oboje musicie skanować nawzajem swoje kody QR</string>
<!--Adding Contacts Remotely--> <!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Dodaj Kontakt na odległość</string> <string name="add_contact_remotely_title_case">Dodaj Kontakt na odległość</string>
<string name="add_contact_nearby_title">Dodaj kontakt w pobliżu</string> <string name="add_contact_nearby_title">Dodaj kontakt w pobliżu</string>
@@ -320,7 +318,6 @@
<string name="different_person_button">Inna osoba</string> <string name="different_person_button">Inna osoba</string>
<string name="duplicate_link_dialog_text_3">%1$si %2$s wysłał ci ten sam link.\n\nJeden z nich może próbować odkryć, kim są twoje kontakty.\n\nNie mów im, że otrzymałeś ten sam link od kogoś innego.</string> <string name="duplicate_link_dialog_text_3">%1$si %2$s wysłał ci ten sam link.\n\nJeden z nich może próbować odkryć, kim są twoje kontakty.\n\nNie mów im, że otrzymałeś ten sam link od kogoś innego.</string>
<string name="pending_contact_updated_toast">Oczekujący kontakt zaktualizowany</string> <string name="pending_contact_updated_toast">Oczekujący kontakt zaktualizowany</string>
<string name="info_both_must_enter_links">Oboje musicie dodać swoje linki</string>
<!--Peer trust levels--> <!--Peer trust levels-->
<string name="peer_trust_level_unverified">Niezweryfikowane kontakty</string> <string name="peer_trust_level_unverified">Niezweryfikowane kontakty</string>
<string name="peer_trust_level_verified">Zweryfikowane kontakty</string> <string name="peer_trust_level_verified">Zweryfikowane kontakty</string>
@@ -354,7 +351,6 @@
<string name="connect_via_bluetooth_intro">W przypadku gdy połączenia przez Bluetooth nie działają automatycznie, możesz użyć tego ekranu do połączenia ręcznego.\n\nTwój kontakt musi znajdować się w pobliżu, żeby to zadziałało.\n\nTy i Twój kontakt powinniście jednocześnie wcisnąć \"Start\".</string> <string name="connect_via_bluetooth_intro">W przypadku gdy połączenia przez Bluetooth nie działają automatycznie, możesz użyć tego ekranu do połączenia ręcznego.\n\nTwój kontakt musi znajdować się w pobliżu, żeby to zadziałało.\n\nTy i Twój kontakt powinniście jednocześnie wcisnąć \"Start\".</string>
<string name="connect_via_bluetooth_already_discovering">Próba połączenia przez Bluetooth jest już w trakcie. Spróbuj ponownie za chwilę.</string> <string name="connect_via_bluetooth_already_discovering">Próba połączenia przez Bluetooth jest już w trakcie. Spróbuj ponownie za chwilę.</string>
<string name="connect_via_bluetooth_no_location_permission">Nie można kontynuować bez dostępu do lokalizacji</string> <string name="connect_via_bluetooth_no_location_permission">Nie można kontynuować bez dostępu do lokalizacji</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">Nie można kontynuować bez pozwolenia na urządzenia w pobliżu</string>
<string name="connect_via_bluetooth_start">Łączenie przez Bluetooth...</string> <string name="connect_via_bluetooth_start">Łączenie przez Bluetooth...</string>
<string name="connect_via_bluetooth_success">Udało się połączyć przez Bluetooth.</string> <string name="connect_via_bluetooth_success">Udało się połączyć przez Bluetooth.</string>
<string name="connect_via_bluetooth_error">Nie można się połączyć przez Bluetooth.</string> <string name="connect_via_bluetooth_error">Nie można się połączyć przez Bluetooth.</string>
@@ -457,10 +453,6 @@
<string name="forum_declined_toast">Zaproszenie odrzucone</string> <string name="forum_declined_toast">Zaproszenie odrzucone</string>
<string name="shared_by_format">Udostępnione przez %s</string> <string name="shared_by_format">Udostępnione przez %s</string>
<string name="forum_invitation_already_sharing">Już udostępnione</string> <string name="forum_invitation_already_sharing">Już udostępnione</string>
<string name="forum_invitation_already_invited">Wysłano już zaproszenie</string>
<string name="forum_invitation_invite_received">Odebrano już zaproszenie</string>
<string name="forum_invitation_not_supported">Nie obsługiwane przez ten kontakt</string>
<string name="forum_invitation_error">Błąd. Jest to błąd w naszej aplikacji, to nie twoja wina</string>
<string name="forum_invitation_response_accepted_sent">Przyjąłeś zaproszenie do forum od %s</string> <string name="forum_invitation_response_accepted_sent">Przyjąłeś zaproszenie do forum od %s</string>
<string name="forum_invitation_response_declined_sent">Odrzuciłeś zaproszenie do forum od %s</string> <string name="forum_invitation_response_declined_sent">Odrzuciłeś zaproszenie do forum od %s</string>
<string name="forum_invitation_response_declined_auto">Zaproszenie do forum od %s zostało automatycznie odrzucone.</string> <string name="forum_invitation_response_declined_auto">Zaproszenie do forum od %s zostało automatycznie odrzucone.</string>
@@ -513,9 +505,8 @@
<string name="blogs_rss_feeds_import">Zaimportuj kanał RSS</string> <string name="blogs_rss_feeds_import">Zaimportuj kanał RSS</string>
<string name="blogs_rss_feeds_import_button">Zaimportuj</string> <string name="blogs_rss_feeds_import_button">Zaimportuj</string>
<string name="blogs_rss_feeds_import_hint">Wprowadź adres URL do kanału RSS</string> <string name="blogs_rss_feeds_import_hint">Wprowadź adres URL do kanału RSS</string>
<string name="blogs_rss_feeds_import_progress">Importowanie kanału RSS…</string>
<string name="blogs_rss_feeds_import_error">Przepraszamy! Wystąpił błąd podczas importowania twojego kanału RSS</string> <string name="blogs_rss_feeds_import_error">Przepraszamy! Wystąpił błąd podczas importowania twojego kanału RSS</string>
<string name="blogs_rss_feeds_import_title">Importuj kanał z pliku</string> <string name="blogs_rss_feeds_import_exists">Ten feed został już zaimportowany.</string>
<string name="blogs_rss_feeds">Feedy RSS</string> <string name="blogs_rss_feeds">Feedy RSS</string>
<string name="blogs_rss_feeds_manage_imported">Zaimportowane:</string> <string name="blogs_rss_feeds_manage_imported">Zaimportowane:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>
@@ -627,9 +618,7 @@
<string name="mailbox_setup_download_link">Udostępnij łącze pobierania</string> <string name="mailbox_setup_download_link">Udostępnij łącze pobierania</string>
<string name="mailbox_setup_button_scan">Zeskanuj kod QR aplikacji Mailbox</string> <string name="mailbox_setup_button_scan">Zeskanuj kod QR aplikacji Mailbox</string>
<string name="permission_camera_qr_denied_body">Odmówiłeś dostępu do aparatu, ale zeskanowanie kodu QR wymaga użycia aparatu.\n\nRozważ przyznanie dostępu.</string> <string name="permission_camera_qr_denied_body">Odmówiłeś dostępu do aparatu, ale zeskanowanie kodu QR wymaga użycia aparatu.\n\nRozważ przyznanie dostępu.</string>
<string name="mailbox_setup_connecting">Łączenie się ze Skrzynką odbiorczą…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Może to potrwać do %1s</string>
<string name="mailbox_setup_already_paired_title">Mailbox już podłączony</string> <string name="mailbox_setup_already_paired_title">Mailbox już podłączony</string>
<string name="mailbox_setup_already_paired_description">Odłącz Mailbox na drugim urządzeniu i spróbuj ponownie.</string> <string name="mailbox_setup_already_paired_description">Odłącz Mailbox na drugim urządzeniu i spróbuj ponownie.</string>
<string name="mailbox_setup_io_error_title">Nie udało się połączyć</string> <string name="mailbox_setup_io_error_title">Nie udało się połączyć</string>
@@ -767,15 +756,11 @@ Brak dostępu do aparatu. Spróbuj ponownie, może po ponownym uruchomieniu urz
<string name="permission_location_request_body">Aby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do twojej lokalizacji.\n\nBriar nie przechowuje twojej lokalizacji ani nie udostępnia jej nikomu.</string> <string name="permission_location_request_body">Aby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do twojej lokalizacji.\n\nBriar nie przechowuje twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_camera_location_title">Kamera i lokalizacja</string> <string name="permission_camera_location_title">Kamera i lokalizacja</string>
<string name="permission_camera_location_request_body">Aby zeskanować kod QR, Briar potrzebuje dostępu do kamery.\n\nAby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do Twojej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string> <string name="permission_camera_location_request_body">Aby zeskanować kod QR, Briar potrzebuje dostępu do kamery.\n\nAby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do Twojej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_camera_bluetooth_title">Aparat i urządzenia w pobliżu</string>
<string name="permission_camera_denied_body">Odmówiłeś dostępu do aparatu, lecz dodawanie kontaktów wymaga jego użycia.\n\nProszę rozważyć udzielenie dostępu do aparatu</string> <string name="permission_camera_denied_body">Odmówiłeś dostępu do aparatu, lecz dodawanie kontaktów wymaga jego użycia.\n\nProszę rozważyć udzielenie dostępu do aparatu</string>
<string name="permission_location_denied_body">Zabroniłeś dostępu do Twojej lokalizacji, ale Briar potrzebuje tego uprawnienia do wykrywania urządzeń Bluetooth.\n\nRozważ przyznanie tego dostępu.</string> <string name="permission_location_denied_body">Zabroniłeś dostępu do Twojej lokalizacji, ale Briar potrzebuje tego uprawnienia do wykrywania urządzeń Bluetooth.\n\nRozważ przyznanie tego dostępu.</string>
<string name="permission_location_setting_title">Ustawienia lokalizacji</string> <string name="permission_location_setting_title">Ustawienia lokalizacji</string>
<string name="permission_location_setting_body">Ustawienie lokalizacji urządzenia musi być włączone, aby można było znaleźć inne urządzenia przez Bluetooth. Włącz lokalizację, aby kontynuować. Później możesz ją ponownie wyłączyć.</string> <string name="permission_location_setting_body">Ustawienie lokalizacji urządzenia musi być włączone, aby można było znaleźć inne urządzenia przez Bluetooth. Włącz lokalizację, aby kontynuować. Później możesz ją ponownie wyłączyć.</string>
<string name="permission_location_setting_button">Włącz lokalizację</string> <string name="permission_location_setting_button">Włącz lokalizację</string>
<string name="permission_bluetooth_title">Pozwolenie do urządzeń w pobliżu</string>
<string name="permission_bluetooth_body">Aby korzystać z komunikacji Bluetooth, Briar potrzebuje uprawnień do znajdowania i łączenia się z pobliskimi urządzeniami.</string>
<string name="permission_bluetooth_denied_body">Odmówiono dostępu do pobliskich urządzeń, ale Briar potrzebuje tego uprawnienia, aby korzystać z Bluetooth.\n\nRozważ udzielenie dostępu.</string>
<string name="qr_code">Kod QR</string> <string name="qr_code">Kod QR</string>
<string name="show_qr_code_fullscreen">Pokaż QR na pełnym ekranie</string> <string name="show_qr_code_fullscreen">Pokaż QR na pełnym ekranie</string>
<!--App Locking--> <!--App Locking-->

View File

@@ -488,6 +488,7 @@
<string name="blogs_rss_feeds_import_button">Importar</string> <string name="blogs_rss_feeds_import_button">Importar</string>
<string name="blogs_rss_feeds_import_hint">Entre a URL do feed RSS</string> <string name="blogs_rss_feeds_import_hint">Entre a URL do feed RSS</string>
<string name="blogs_rss_feeds_import_error">Nós lamentamos! Houve um erro ao importar seu Feed.</string> <string name="blogs_rss_feeds_import_error">Nós lamentamos! Houve um erro ao importar seu Feed.</string>
<string name="blogs_rss_feeds_import_exists">Esse feed já foi importado.</string>
<string name="blogs_rss_feeds">Feeds RSS</string> <string name="blogs_rss_feeds">Feeds RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importado:</string> <string name="blogs_rss_feeds_manage_imported">Importado:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -446,10 +446,6 @@
<string name="forum_declined_toast">Invitația a fost refuzată</string> <string name="forum_declined_toast">Invitația a fost refuzată</string>
<string name="shared_by_format">Partajat de %s</string> <string name="shared_by_format">Partajat de %s</string>
<string name="forum_invitation_already_sharing">Deja partajat</string> <string name="forum_invitation_already_sharing">Deja partajat</string>
<string name="forum_invitation_already_invited">Invitație deja trimisă</string>
<string name="forum_invitation_invite_received">Invitație deja primită</string>
<string name="forum_invitation_not_supported">Nu este susținut de acest contact</string>
<string name="forum_invitation_error">Eroare. Aceasta este o eroare și nu este vina dumneavoastră</string>
<string name="forum_invitation_response_accepted_sent">Ați acceptat invitația la forum de la %s.</string> <string name="forum_invitation_response_accepted_sent">Ați acceptat invitația la forum de la %s.</string>
<string name="forum_invitation_response_declined_sent">Ați refuzat invitația la forum de la %s.</string> <string name="forum_invitation_response_declined_sent">Ați refuzat invitația la forum de la %s.</string>
<string name="forum_invitation_response_declined_auto">Invitația la forumu de la %s a fost refuzată automat.</string> <string name="forum_invitation_response_declined_auto">Invitația la forumu de la %s a fost refuzată automat.</string>
@@ -501,9 +497,8 @@
<string name="blogs_rss_feeds_import">Importați flux RSS</string> <string name="blogs_rss_feeds_import">Importați flux RSS</string>
<string name="blogs_rss_feeds_import_button">Importați</string> <string name="blogs_rss_feeds_import_button">Importați</string>
<string name="blogs_rss_feeds_import_hint">Introduceți adresa URL a fluxului RSS</string> <string name="blogs_rss_feeds_import_hint">Introduceți adresa URL a fluxului RSS</string>
<string name="blogs_rss_feeds_import_progress">Importarea RSS Feed…</string>
<string name="blogs_rss_feeds_import_error">Ne pare rău, dar a apărut o eroare la importarea fluxului dvs.</string> <string name="blogs_rss_feeds_import_error">Ne pare rău, dar a apărut o eroare la importarea fluxului dvs.</string>
<string name="blogs_rss_feeds_import_title">Importați feed din fișier</string> <string name="blogs_rss_feeds_import_exists">Fluxul respectiv este deja importat.</string>
<string name="blogs_rss_feeds">Fluxuri RSS</string> <string name="blogs_rss_feeds">Fluxuri RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importat:</string> <string name="blogs_rss_feeds_manage_imported">Importat:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -462,7 +462,7 @@
<string name="forum_invitation_already_invited">Приглашение уже отправлено</string> <string name="forum_invitation_already_invited">Приглашение уже отправлено</string>
<string name="forum_invitation_invite_received">Приглашение уже получено</string> <string name="forum_invitation_invite_received">Приглашение уже получено</string>
<string name="forum_invitation_not_supported">Не поддерживается этим контактом</string> <string name="forum_invitation_not_supported">Не поддерживается этим контактом</string>
<string name="forum_invitation_error">Это ошибка программы. Вы тут ни причем.</string> <string name="forum_invitation_error">Ошибка. Это программная ошибка, а не ваша вина</string>
<string name="forum_invitation_response_accepted_sent">Вы приняли приглашение на форум от %s.</string> <string name="forum_invitation_response_accepted_sent">Вы приняли приглашение на форум от %s.</string>
<string name="forum_invitation_response_declined_sent">Вы отклонили приглашение на форум от %s.</string> <string name="forum_invitation_response_declined_sent">Вы отклонили приглашение на форум от %s.</string>
<string name="forum_invitation_response_declined_auto">Приглашение на форум от %s было отклонено автоматически.</string> <string name="forum_invitation_response_declined_auto">Приглашение на форум от %s было отклонено автоматически.</string>
@@ -515,9 +515,8 @@
<string name="blogs_rss_feeds_import">Импорт RSS-ленты</string> <string name="blogs_rss_feeds_import">Импорт RSS-ленты</string>
<string name="blogs_rss_feeds_import_button">Импорт</string> <string name="blogs_rss_feeds_import_button">Импорт</string>
<string name="blogs_rss_feeds_import_hint">Введите URL-адрес RSS-ленты</string> <string name="blogs_rss_feeds_import_hint">Введите URL-адрес RSS-ленты</string>
<string name="blogs_rss_feeds_import_progress">Импорт RSS-лент...</string>
<string name="blogs_rss_feeds_import_error">Мы сожалеем! Произошла ошибка при импорте ленты.</string> <string name="blogs_rss_feeds_import_error">Мы сожалеем! Произошла ошибка при импорте ленты.</string>
<string name="blogs_rss_feeds_import_title">Импорт ленты из файла</string> <string name="blogs_rss_feeds_import_exists">Эта лента уже импортирована.</string>
<string name="blogs_rss_feeds">RSS-ленты</string> <string name="blogs_rss_feeds">RSS-ленты</string>
<string name="blogs_rss_feeds_manage_imported">Импортирован:</string> <string name="blogs_rss_feeds_manage_imported">Импортирован:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string> <string name="blogs_rss_feeds_manage_author">Автор:</string>

View File

@@ -488,9 +488,8 @@ dhe smund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
<string name="blogs_rss_feeds_import">Importoni Prurje RSS</string> <string name="blogs_rss_feeds_import">Importoni Prurje RSS</string>
<string name="blogs_rss_feeds_import_button">Importo</string> <string name="blogs_rss_feeds_import_button">Importo</string>
<string name="blogs_rss_feeds_import_hint">Jepni URL-në e prurjes RSS</string> <string name="blogs_rss_feeds_import_hint">Jepni URL-në e prurjes RSS</string>
<string name="blogs_rss_feeds_import_progress">Po importohet Prurje RSS…</string>
<string name="blogs_rss_feeds_import_error">Na ndjeni! Pati një gabim me importimin e prurjes tuaj.</string> <string name="blogs_rss_feeds_import_error">Na ndjeni! Pati një gabim me importimin e prurjes tuaj.</string>
<string name="blogs_rss_feeds_import_title">Importo prurje nga kartelë</string> <string name="blogs_rss_feeds_import_exists">Ajo prurje është importuar tashmë.</string>
<string name="blogs_rss_feeds">Prurje RSS</string> <string name="blogs_rss_feeds">Prurje RSS</string>
<string name="blogs_rss_feeds_manage_imported">Të importuara:</string> <string name="blogs_rss_feeds_manage_imported">Të importuara:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -478,6 +478,7 @@ Vänlige installera Briar på en nyare enhet.</string>
<string name="blogs_rss_feeds_import_button">Importera</string> <string name="blogs_rss_feeds_import_button">Importera</string>
<string name="blogs_rss_feeds_import_hint">Skriv URL till RSS-flödet</string> <string name="blogs_rss_feeds_import_hint">Skriv URL till RSS-flödet</string>
<string name="blogs_rss_feeds_import_error">Tyvärr! Något gick fel när flödet skulle importeras.</string> <string name="blogs_rss_feeds_import_error">Tyvärr! Något gick fel när flödet skulle importeras.</string>
<string name="blogs_rss_feeds_import_exists">Det flödet importeras redan.</string>
<string name="blogs_rss_feeds">RSS-flöden</string> <string name="blogs_rss_feeds">RSS-flöden</string>
<string name="blogs_rss_feeds_manage_imported">Importerade:</string> <string name="blogs_rss_feeds_manage_imported">Importerade:</string>
<string name="blogs_rss_feeds_manage_author">Författare:</string> <string name="blogs_rss_feeds_manage_author">Författare:</string>

View File

@@ -482,6 +482,7 @@
<string name="blogs_rss_feeds_import_button">İçe Aktar</string> <string name="blogs_rss_feeds_import_button">İçe Aktar</string>
<string name="blogs_rss_feeds_import_hint">RSS beslemesi URL\'sini girin</string> <string name="blogs_rss_feeds_import_hint">RSS beslemesi URL\'sini girin</string>
<string name="blogs_rss_feeds_import_error">Üzgünüz! RSS beslemeniz içe aktarılırken bir hata oluştu.</string> <string name="blogs_rss_feeds_import_error">Üzgünüz! RSS beslemeniz içe aktarılırken bir hata oluştu.</string>
<string name="blogs_rss_feeds_import_exists">Bu besleme zaten içe aktarılmış.</string>
<string name="blogs_rss_feeds">RSS beslemeleri</string> <string name="blogs_rss_feeds">RSS beslemeleri</string>
<string name="blogs_rss_feeds_manage_imported">İçe Aktarıldı:</string> <string name="blogs_rss_feeds_manage_imported">İçe Aktarıldı:</string>
<string name="blogs_rss_feeds_manage_author">Yazar:</string> <string name="blogs_rss_feeds_manage_author">Yazar:</string>
@@ -593,7 +594,9 @@
<string name="mailbox_setup_download_link">İndirme Bağlantısını Paylaş</string> <string name="mailbox_setup_download_link">İndirme Bağlantısını Paylaş</string>
<string name="mailbox_setup_button_scan">Mailbox Karekodunu Tara</string> <string name="mailbox_setup_button_scan">Mailbox Karekodunu Tara</string>
<string name="permission_camera_qr_denied_body">Kameraya erişimi engellediniz, ancak Mailbox karekodunu taramak için kamerayı kullanmanız gerekiyor.\n\nLütfen erişim izni vermeyi düşünün.</string> <string name="permission_camera_qr_denied_body">Kameraya erişimi engellediniz, ancak Mailbox karekodunu taramak için kamerayı kullanmanız gerekiyor.\n\nLütfen erişim izni vermeyi düşünün.</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <string name="mailbox_setup_connecting">Bağlantı kuruluyor…</string>
<string name="mailbox_setup_qr_code_wrong_title">Yanlış Karekod</string>
<string name="mailbox_setup_qr_code_wrong_description">Taranan kod geçersiz. Lütfen Briar Mailbox uygulamasını Mailbox aygıtınızda açın ve gösterdiği Karekodu tarayın.</string>
<string name="mailbox_setup_already_paired_title">Mailbox zaten bağlanmış</string> <string name="mailbox_setup_already_paired_title">Mailbox zaten bağlanmış</string>
<string name="mailbox_setup_already_paired_description">Diğer aygıttan Mailbox bağlantısını kaldırın ve tekrar deneyin</string> <string name="mailbox_setup_already_paired_description">Diğer aygıttan Mailbox bağlantısını kaldırın ve tekrar deneyin</string>
<string name="mailbox_setup_io_error_title">Bağlantı kurulamıyor</string> <string name="mailbox_setup_io_error_title">Bağlantı kurulamıyor</string>

View File

@@ -505,6 +505,7 @@
<string name="blogs_rss_feeds_import_button">Імпортувати</string> <string name="blogs_rss_feeds_import_button">Імпортувати</string>
<string name="blogs_rss_feeds_import_hint">Введіть URL-посилання RSS-стрічки</string> <string name="blogs_rss_feeds_import_hint">Введіть URL-посилання RSS-стрічки</string>
<string name="blogs_rss_feeds_import_error">Нам шкода! Виникла помилка під час імпорту вашої стрічки.</string> <string name="blogs_rss_feeds_import_error">Нам шкода! Виникла помилка під час імпорту вашої стрічки.</string>
<string name="blogs_rss_feeds_import_exists">Цю стрічку вже імпортовано.</string>
<string name="blogs_rss_feeds">RSS-стрічки</string> <string name="blogs_rss_feeds">RSS-стрічки</string>
<string name="blogs_rss_feeds_manage_imported">Імпортовано:</string> <string name="blogs_rss_feeds_manage_imported">Імпортовано:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string> <string name="blogs_rss_feeds_manage_author">Автор:</string>

View File

@@ -473,9 +473,8 @@
<string name="blogs_rss_feeds_import">导入 RSS 订阅源</string> <string name="blogs_rss_feeds_import">导入 RSS 订阅源</string>
<string name="blogs_rss_feeds_import_button">导入</string> <string name="blogs_rss_feeds_import_button">导入</string>
<string name="blogs_rss_feeds_import_hint">输入 RSS 订阅源链接</string> <string name="blogs_rss_feeds_import_hint">输入 RSS 订阅源链接</string>
<string name="blogs_rss_feeds_import_progress">导入 RSS 订阅源中…</string>
<string name="blogs_rss_feeds_import_error">抱歉!导入订阅源时发生错误。</string> <string name="blogs_rss_feeds_import_error">抱歉!导入订阅源时发生错误。</string>
<string name="blogs_rss_feeds_import_title">从文件导入</string> <string name="blogs_rss_feeds_import_exists">已经导入那个</string>
<string name="blogs_rss_feeds">RSS源 </string> <string name="blogs_rss_feeds">RSS源 </string>
<string name="blogs_rss_feeds_manage_imported">已导入:</string> <string name="blogs_rss_feeds_manage_imported">已导入:</string>
<string name="blogs_rss_feeds_manage_author">作者:</string> <string name="blogs_rss_feeds_manage_author">作者:</string>

View File

@@ -423,10 +423,6 @@
<string name="forum_declined_toast">邀請已謝絕</string> <string name="forum_declined_toast">邀請已謝絕</string>
<string name="shared_by_format">由 %s 分享</string> <string name="shared_by_format">由 %s 分享</string>
<string name="forum_invitation_already_sharing">已在分享</string> <string name="forum_invitation_already_sharing">已在分享</string>
<string name="forum_invitation_already_invited">已發送邀請</string>
<string name="forum_invitation_invite_received">已收到邀請</string>
<string name="forum_invitation_not_supported">此聯絡人無法使用</string>
<string name="forum_invitation_error">出錯,出了點問題與您無關</string>
<string name="forum_invitation_response_accepted_sent">您接受了來自 %s的論壇邀請</string> <string name="forum_invitation_response_accepted_sent">您接受了來自 %s的論壇邀請</string>
<string name="forum_invitation_response_declined_sent">您謝絕了來自 %s的論壇邀請</string> <string name="forum_invitation_response_declined_sent">您謝絕了來自 %s的論壇邀請</string>
<string name="forum_invitation_response_declined_auto">來自%s論壇的邀請已自動拒絕</string> <string name="forum_invitation_response_declined_auto">來自%s論壇的邀請已自動拒絕</string>
@@ -477,6 +473,7 @@
<string name="blogs_rss_feeds_import_button">導入</string> <string name="blogs_rss_feeds_import_button">導入</string>
<string name="blogs_rss_feeds_import_hint">輸入 RSS 訂閱源鏈接</string> <string name="blogs_rss_feeds_import_hint">輸入 RSS 訂閱源鏈接</string>
<string name="blogs_rss_feeds_import_error">抱歉!導入訂閱源時發生錯誤。</string> <string name="blogs_rss_feeds_import_error">抱歉!導入訂閱源時發生錯誤。</string>
<string name="blogs_rss_feeds_import_exists">此來源已滙入</string>
<string name="blogs_rss_feeds">RSS 消息源</string> <string name="blogs_rss_feeds">RSS 消息源</string>
<string name="blogs_rss_feeds_manage_imported">已導入:</string> <string name="blogs_rss_feeds_manage_imported">已導入:</string>
<string name="blogs_rss_feeds_manage_author">作者:</string> <string name="blogs_rss_feeds_manage_author">作者:</string>

View File

@@ -519,9 +519,7 @@
<string name="blogs_rss_feeds_import">Import RSS Feed</string> <string name="blogs_rss_feeds_import">Import RSS Feed</string>
<string name="blogs_rss_feeds_import_button">Import</string> <string name="blogs_rss_feeds_import_button">Import</string>
<string name="blogs_rss_feeds_import_hint">Enter the URL of the RSS feed</string> <string name="blogs_rss_feeds_import_hint">Enter the URL of the RSS feed</string>
<string name="blogs_rss_feeds_import_progress">Importing RSS Feed…</string>
<string name="blogs_rss_feeds_import_error">We are sorry! There was an error importing your feed.</string> <string name="blogs_rss_feeds_import_error">We are sorry! There was an error importing your feed.</string>
<string name="blogs_rss_feeds_import_title">Import feed from file</string>
<string name="blogs_rss_feeds">RSS Feeds</string> <string name="blogs_rss_feeds">RSS Feeds</string>
<string name="blogs_rss_feeds_manage_imported">Imported:</string> <string name="blogs_rss_feeds_manage_imported">Imported:</string>
<string name="blogs_rss_feeds_manage_author">Author:</string> <string name="blogs_rss_feeds_manage_author">Author:</string>

View File

@@ -56,7 +56,7 @@ public class AttachmentReaderImpl implements AttachmentReader {
String contentType = meta.getString(MSG_KEY_CONTENT_TYPE); String contentType = meta.getString(MSG_KEY_CONTENT_TYPE);
if (!contentType.equals(h.getContentType())) if (!contentType.equals(h.getContentType()))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
int offset = meta.getInt(MSG_KEY_DESCRIPTOR_LENGTH); int offset = meta.getLong(MSG_KEY_DESCRIPTOR_LENGTH).intValue();
InputStream stream = new ByteArrayInputStream(body, offset, InputStream stream = new ByteArrayInputStream(body, offset,
body.length - offset); body.length - offset);
return new Attachment(h, stream); return new Attachment(h, stream);

View File

@@ -250,7 +250,7 @@ class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook,
try { try {
BdfDictionary meta = BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g); clientHelper.getGroupMetadataAsDictionary(txn, g);
return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID)); return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }

View File

@@ -76,7 +76,7 @@ class AvatarValidator implements MessageValidator {
// 0.0: Message Type, Version, Content-Type // 0.0: Message Type, Version, Content-Type
checkSize(body, 3); checkSize(body, 3);
// Message Type // Message Type
int messageType = body.getInt(0); long messageType = body.getLong(0);
if (messageType != MSG_TYPE_UPDATE) throw new FormatException(); if (messageType != MSG_TYPE_UPDATE) throw new FormatException();
// Version // Version
long version = body.getLong(1); long version = body.getLong(1);

View File

@@ -487,7 +487,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
} }
private String getPostText(BdfList message) throws FormatException { private String getPostText(BdfList message) throws FormatException {
MessageType type = MessageType.valueOf(message.getInt(0)); MessageType type = MessageType.valueOf(message.getLong(0).intValue());
if (type == POST) { if (type == POST) {
// Type, text, signature // Type, text, signature
return message.getString(1); return message.getString(1);
@@ -621,6 +621,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
} }
private MessageType getMessageType(BdfDictionary d) throws FormatException { private MessageType getMessageType(BdfDictionary d) throws FormatException {
return MessageType.valueOf(d.getInt(KEY_TYPE)); Long longType = d.getLong(KEY_TYPE);
return MessageType.valueOf(longType.intValue());
} }
} }

View File

@@ -167,6 +167,6 @@ class BlogPostFactoryImpl implements BlogPostFactory {
} }
private MessageType getType(BdfList body) throws FormatException { private MessageType getType(BdfList body) throws FormatException {
return MessageType.valueOf(body.getInt(0)); return MessageType.valueOf(body.getLong(0).intValue());
} }
} }

View File

@@ -72,7 +72,7 @@ class BlogPostValidator extends BdfMessageValidator {
BdfMessageContext c; BdfMessageContext c;
int type = body.getInt(0); int type = body.getLong(0).intValue();
body.remove(0); body.remove(0);
switch (MessageType.valueOf(type)) { switch (MessageType.valueOf(type)) {
case POST: case POST:

View File

@@ -114,8 +114,8 @@ class MessageTrackerImpl implements MessageTracker {
try { try {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g); BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
return new GroupCount( return new GroupCount(
d.getInt(GROUP_KEY_MSG_COUNT, 0), d.getLong(GROUP_KEY_MSG_COUNT, 0L).intValue(),
d.getInt(GROUP_KEY_UNREAD_COUNT, 0), d.getLong(GROUP_KEY_UNREAD_COUNT, 0L).intValue(),
d.getLong(GROUP_KEY_LATEST_MSG, 0L) d.getLong(GROUP_KEY_LATEST_MSG, 0L)
); );
} catch (FormatException e) { } catch (FormatException e) {

View File

@@ -47,7 +47,7 @@ class IntroductionValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getInt(0)); MessageType type = MessageType.fromValue(body.getLong(0).intValue());
switch (type) { switch (type) {
case REQUEST: case REQUEST:

View File

@@ -59,8 +59,8 @@ class MessageParserImpl implements MessageParser {
@Override @Override
public MessageMetadata parseMetadata(BdfDictionary d) public MessageMetadata parseMetadata(BdfDictionary d)
throws FormatException { throws FormatException {
MessageType type = MessageType type = MessageType
MessageType.fromValue(d.getInt(MSG_KEY_MESSAGE_TYPE)); .fromValue(d.getLong(MSG_KEY_MESSAGE_TYPE).intValue());
byte[] sessionIdBytes = d.getOptionalRaw(MSG_KEY_SESSION_ID); byte[] sessionIdBytes = d.getOptionalRaw(MSG_KEY_SESSION_ID);
SessionId sessionId = SessionId sessionId =
sessionIdBytes == null ? null : new SessionId(sessionIdBytes); sessionIdBytes == null ? null : new SessionId(sessionIdBytes);

View File

@@ -72,7 +72,7 @@ class SessionParserImpl implements SessionParser {
@Override @Override
public Role getRole(BdfDictionary d) throws FormatException { public Role getRole(BdfDictionary d) throws FormatException {
return Role.fromValue(d.getInt(SESSION_KEY_ROLE)); return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue());
} }
@Override @Override
@@ -97,7 +97,7 @@ class SessionParserImpl implements SessionParser {
MessageId lastRemoteMessageId = MessageId lastRemoteMessageId =
getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID);
long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP);
GroupId groupId = getGroupId(d); GroupId groupId = getGroupId(d, SESSION_KEY_GROUP_ID);
Author author = getAuthor(d, SESSION_KEY_AUTHOR); Author author = getAuthor(d, SESSION_KEY_AUTHOR);
return new Introducee(sessionId, groupId, author, localTimestamp, return new Introducee(sessionId, groupId, author, localTimestamp,
lastLocalMessageId, lastRemoteMessageId); lastLocalMessageId, lastRemoteMessageId);
@@ -126,10 +126,12 @@ class SessionParserImpl implements SessionParser {
MessageId lastLocalMessageId = MessageId lastLocalMessageId =
getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID);
long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP);
PublicKey ephemeralPublicKey = getEphemeralPublicKey(d); PublicKey ephemeralPublicKey =
getEphemeralPublicKey(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
BdfDictionary tpDict = BdfDictionary tpDict =
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
PrivateKey ephemeralPrivateKey = getEphemeralPrivateKey(d); PrivateKey ephemeralPrivateKey =
getEphemeralPrivateKey(d, SESSION_KEY_EPHEMERAL_PRIVATE_KEY);
Map<TransportId, TransportProperties> transportProperties = Map<TransportId, TransportProperties> transportProperties =
tpDict == null ? null : clientHelper tpDict == null ? null : clientHelper
.parseAndValidateTransportPropertiesMap(tpDict); .parseAndValidateTransportPropertiesMap(tpDict);
@@ -145,7 +147,8 @@ class SessionParserImpl implements SessionParser {
Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR); Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR);
MessageId lastRemoteMessageId = MessageId lastRemoteMessageId =
getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID);
PublicKey ephemeralPublicKey = getEphemeralPublicKey(d); PublicKey ephemeralPublicKey =
getEphemeralPublicKey(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
BdfDictionary tpDict = BdfDictionary tpDict =
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
Map<TransportId, TransportProperties> transportProperties = Map<TransportId, TransportProperties> transportProperties =
@@ -159,7 +162,7 @@ class SessionParserImpl implements SessionParser {
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {
return d.getInt(SESSION_KEY_STATE); return d.getLong(SESSION_KEY_STATE).intValue();
} }
private SessionId getSessionId(BdfDictionary d) throws FormatException { private SessionId getSessionId(BdfDictionary d) throws FormatException {
@@ -174,8 +177,9 @@ class SessionParserImpl implements SessionParser {
return b == null ? null : new MessageId(b); return b == null ? null : new MessageId(b);
} }
private GroupId getGroupId(BdfDictionary d) throws FormatException { private GroupId getGroupId(BdfDictionary d, String key)
return new GroupId(d.getRaw(SESSION_KEY_GROUP_ID)); throws FormatException {
return new GroupId(d.getRaw(key));
} }
private Author getAuthor(BdfDictionary d, String key) private Author getAuthor(BdfDictionary d, String key)
@@ -189,22 +193,23 @@ class SessionParserImpl implements SessionParser {
if (d == null) return null; if (d == null) return null;
Map<TransportId, KeySetId> map = new HashMap<>(d.size()); Map<TransportId, KeySetId> map = new HashMap<>(d.size());
for (String key : d.keySet()) { for (String key : d.keySet()) {
map.put(new TransportId(key), new KeySetId(d.getInt(key))); map.put(new TransportId(key),
new KeySetId(d.getLong(key).intValue()));
} }
return map; return map;
} }
@Nullable @Nullable
private PublicKey getEphemeralPublicKey(BdfDictionary d) private PublicKey getEphemeralPublicKey(BdfDictionary d, String key)
throws FormatException { throws FormatException {
byte[] keyBytes = d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY); byte[] keyBytes = d.getOptionalRaw(key);
return keyBytes == null ? null : new AgreementPublicKey(keyBytes); return keyBytes == null ? null : new AgreementPublicKey(keyBytes);
} }
@Nullable @Nullable
private PrivateKey getEphemeralPrivateKey(BdfDictionary d) private PrivateKey getEphemeralPrivateKey(BdfDictionary d, String key)
throws FormatException { throws FormatException {
byte[] keyBytes = d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PRIVATE_KEY); byte[] keyBytes = d.getOptionalRaw(key);
return keyBytes == null ? null : new AgreementPrivateKey(keyBytes); return keyBytes == null ? null : new AgreementPrivateKey(keyBytes);
} }
} }

View File

@@ -182,7 +182,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
try { try {
BdfDictionary metaDict = metadataParser.parse(meta); BdfDictionary metaDict = metadataParser.parse(meta);
// Message type is null for version 0.0 private messages // Message type is null for version 0.0 private messages
Integer messageType = metaDict.getOptionalInt(MSG_KEY_MSG_TYPE); Long messageType = metaDict.getOptionalLong(MSG_KEY_MSG_TYPE);
if (messageType == null) { if (messageType == null) {
incomingPrivateMessage(txn, m, metaDict, true, emptyList()); incomingPrivateMessage(txn, m, metaDict, true, emptyList());
} else if (messageType == PRIVATE_MESSAGE) { } else if (messageType == PRIVATE_MESSAGE) {
@@ -371,7 +371,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
try { try {
BdfDictionary meta = BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g); clientHelper.getGroupMetadataAsDictionary(txn, g);
return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID)); return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -381,7 +381,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
public ContactId getContactId(GroupId g) throws DbException { public ContactId getContactId(GroupId g) throws DbException {
try { try {
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g); BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g);
return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID)); return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -419,7 +419,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
if (meta == null) continue; if (meta == null) continue;
try { try {
// Message type is null for version 0.0 private messages // Message type is null for version 0.0 private messages
Integer messageType = meta.getOptionalInt(MSG_KEY_MSG_TYPE); Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE);
if (messageType != null && messageType != PRIVATE_MESSAGE) if (messageType != null && messageType != PRIVATE_MESSAGE)
continue; continue;
long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); long timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
@@ -453,8 +453,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
Map<MessageId, BdfDictionary> messages = Map<MessageId, BdfDictionary> messages =
clientHelper.getMessageMetadataAsDictionary(txn, g); clientHelper.getMessageMetadataAsDictionary(txn, g);
for (Entry<MessageId, BdfDictionary> entry : messages.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : messages.entrySet()) {
Integer type = Long type = entry.getValue().getOptionalLong(MSG_KEY_MSG_TYPE);
entry.getValue().getOptionalInt(MSG_KEY_MSG_TYPE);
if (type == null || type == PRIVATE_MESSAGE) if (type == null || type == PRIVATE_MESSAGE)
result.add(entry.getKey()); result.add(entry.getKey());
} }
@@ -528,7 +527,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
try { try {
BdfDictionary meta = BdfDictionary meta =
clientHelper.getMessageMetadataAsDictionary(txn, m); clientHelper.getMessageMetadataAsDictionary(txn, m);
Integer messageType = meta.getOptionalInt(MSG_KEY_MSG_TYPE); Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE);
if (messageType != null && messageType == PRIVATE_MESSAGE) { if (messageType != null && messageType == PRIVATE_MESSAGE) {
for (AttachmentHeader h : parseAttachmentHeaders(g, meta)) { for (AttachmentHeader h : parseAttachmentHeaders(g, meta)) {
try { try {
@@ -555,7 +554,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
int unreadCount = 0; int unreadCount = 0;
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfDictionary meta = entry.getValue(); BdfDictionary meta = entry.getValue();
Integer messageType = meta.getOptionalInt(MSG_KEY_MSG_TYPE); Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE);
if (messageType == null || messageType == PRIVATE_MESSAGE) { if (messageType == null || messageType == PRIVATE_MESSAGE) {
msgCount++; msgCount++;
if (!meta.getBoolean(MSG_KEY_READ)) unreadCount++; if (!meta.getBoolean(MSG_KEY_READ)) unreadCount++;

View File

@@ -84,7 +84,7 @@ class PrivateMessageValidator implements MessageValidator {
context = validateLegacyPrivateMessage(m, list); context = validateLegacyPrivateMessage(m, list);
} else { } else {
// Private message or attachment // Private message or attachment
int messageType = list.getInt(0); int messageType = list.getLong(0).intValue();
if (messageType == PRIVATE_MESSAGE) { if (messageType == PRIVATE_MESSAGE) {
if (!reader.eof()) throw new FormatException(); if (!reader.eof()) throw new FormatException();
context = validatePrivateMessage(m, list); context = validatePrivateMessage(m, list);

View File

@@ -63,7 +63,7 @@ class GroupMessageValidator extends BdfMessageValidator {
checkSize(body, 4, 6); checkSize(body, 4, 6);
// Message type (int) // Message type (int)
int type = body.getInt(0); int type = body.getLong(0).intValue();
// Member (author) // Member (author)
BdfList memberList = body.getList(1); BdfList memberList = body.getList(1);

View File

@@ -366,7 +366,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
// parse the metadata // parse the metadata
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfDictionary meta = entry.getValue(); BdfDictionary meta = entry.getValue();
if (meta.getInt(KEY_TYPE) == JOIN.getInt()) { if (meta.getLong(KEY_TYPE) == JOIN.getInt()) {
headers.add(getJoinMessageHeader(txn, g, entry.getKey(), headers.add(getJoinMessageHeader(txn, g, entry.getKey(),
meta, authorInfos)); meta, authorInfos));
} else { } else {
@@ -530,7 +530,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
BdfList body, BdfDictionary meta) BdfList body, BdfDictionary meta)
throws DbException, FormatException { throws DbException, FormatException {
MessageType type = MessageType.valueOf(meta.getInt(KEY_TYPE)); MessageType type =
MessageType.valueOf(meta.getLong(KEY_TYPE).intValue());
switch (type) { switch (type) {
case JOIN: case JOIN:
handleJoinMessage(txn, m, meta); handleJoinMessage(txn, m, meta);
@@ -575,8 +576,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
.getMessageMetadataAsDictionary(txn, parentId); .getMessageMetadataAsDictionary(txn, parentId);
if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP)) if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP))
throw new FormatException(); throw new FormatException();
MessageType parentType = MessageType parentType = MessageType
MessageType.valueOf(parentMeta.getInt(KEY_TYPE)); .valueOf(parentMeta.getLong(KEY_TYPE).intValue());
if (parentType != POST) if (parentType != POST)
throw new FormatException(); throw new FormatException();
} }
@@ -591,8 +592,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
if (!getAuthor(meta).equals(getAuthor(previousMeta))) if (!getAuthor(meta).equals(getAuthor(previousMeta)))
throw new FormatException(); throw new FormatException();
// previous message must be a POST or JOIN // previous message must be a POST or JOIN
MessageType previousType = MessageType previousType = MessageType
MessageType.valueOf(previousMeta.getInt(KEY_TYPE)); .valueOf(previousMeta.getLong(KEY_TYPE).intValue());
if (previousType != JOIN && previousType != POST) if (previousType != JOIN && previousType != POST)
throw new FormatException(); throw new FormatException();
// track message and broadcast event // track message and broadcast event
@@ -640,7 +641,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
private Visibility getVisibility(BdfDictionary meta) private Visibility getVisibility(BdfDictionary meta)
throws FormatException { throws FormatException {
return Visibility.valueOf(meta.getInt(GROUP_KEY_VISIBILITY)); return Visibility
.valueOf(meta.getLong(GROUP_KEY_VISIBILITY).intValue());
} }
} }

View File

@@ -2,6 +2,12 @@ package org.briarproject.briar.privategroup.invitation;
interface GroupInvitationConstants { interface GroupInvitationConstants {
/**
* Metadata key for the client's local group, indicating that contact
* groups have been created for all contacts.
*/
String GROUP_KEY_SETUP = "setup";
// Message metadata keys // Message metadata keys
String MSG_KEY_MESSAGE_TYPE = "messageType"; String MSG_KEY_MESSAGE_TYPE = "messageType";
String MSG_KEY_PRIVATE_GROUP_ID = "privateGroupId"; String MSG_KEY_PRIVATE_GROUP_ID = "privateGroupId";

View File

@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager.ContactHook; import org.briarproject.bramble.api.contact.ContactManager.ContactHook;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataParser; import org.briarproject.bramble.api.data.MetadataParser;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
@@ -63,6 +64,7 @@ import static org.briarproject.briar.privategroup.invitation.CreatorState.ERROR;
import static org.briarproject.briar.privategroup.invitation.CreatorState.INVITED; import static org.briarproject.briar.privategroup.invitation.CreatorState.INVITED;
import static org.briarproject.briar.privategroup.invitation.CreatorState.JOINED; import static org.briarproject.briar.privategroup.invitation.CreatorState.JOINED;
import static org.briarproject.briar.privategroup.invitation.CreatorState.START; import static org.briarproject.briar.privategroup.invitation.CreatorState.START;
import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_SETUP;
import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN;
@@ -114,13 +116,35 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
@Override @Override
public void onDatabaseOpened(Transaction txn) throws DbException { public void onDatabaseOpened(Transaction txn) throws DbException {
// Create a local group to indicate that we've set this client up // If the feature flag for this client was set and then cleared, we may
// have set things up for some pre-existing contacts and not others.
// If the local group exists and has GROUP_KEY_SETUP == true in its
// metadata then we've set things up for all contacts. Otherwise we
// need to check whether a contact group exists for each contact.
Group localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID, Group localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID,
MAJOR_VERSION); MAJOR_VERSION);
if (db.containsGroup(txn, localGroup.getId())) return; try {
db.addGroup(txn, localGroup); if (db.containsGroup(txn, localGroup.getId())) {
// Set things up for any pre-existing contacts // If GROUP_KEY_SETUP == true then we're done
for (Contact c : db.getContacts(txn)) addingContact(txn, c); BdfDictionary meta = clientHelper
.getGroupMetadataAsDictionary(txn, localGroup.getId());
if (meta.getBoolean(GROUP_KEY_SETUP, false)) return;
} else {
db.addGroup(txn, localGroup);
}
BdfDictionary meta =
BdfDictionary.of(new BdfEntry(GROUP_KEY_SETUP, true));
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
} catch (FormatException e) {
throw new DbException(e);
}
// Set things up for any contacts that haven't already been set up
for (Contact c : db.getContacts(txn)) {
Group contactGroup = getContactGroup(c);
if (!db.containsGroup(txn, contactGroup.getId())) {
addingContact(txn, c);
}
}
} }
@Override @Override
@@ -712,9 +736,9 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
// get all sessions and their states // get all sessions and their states
Map<GroupId, DeletableSession> sessions = new HashMap<>(); Map<GroupId, DeletableSession> sessions = new HashMap<>();
for (BdfDictionary d : metadata.values()) { for (BdfDictionary d : metadata.values()) {
if (!sessionParser.isSession(d)) continue;
Session<?> session; Session<?> session;
try { try {
if (!sessionParser.isSession(d)) continue;
session = sessionParser.parseSession(g, d); session = sessionParser.parseSession(g, d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
@@ -776,12 +800,13 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
// assign protocol messages to their sessions // assign protocol messages to their sessions
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
// parse message metadata and skip messages not visible in UI // parse message metadata and skip messages not visible in UI
MessageMetadata m; MessageMetadata m;
try { try {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
m = messageParser.parseMetadata(d); m = messageParser.parseMetadata(d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);

View File

@@ -56,7 +56,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getInt(0)); MessageType type = MessageType.fromValue(body.getLong(0).intValue());
switch (type) { switch (type) {
case INVITE: case INVITE:
return validateInviteMessage(m, body); return validateInviteMessage(m, body);

View File

@@ -71,8 +71,8 @@ class MessageParserImpl implements MessageParser {
@Override @Override
public MessageMetadata parseMetadata(BdfDictionary meta) public MessageMetadata parseMetadata(BdfDictionary meta)
throws FormatException { throws FormatException {
MessageType type = MessageType type = MessageType.fromValue(
MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE)); meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue());
GroupId privateGroupId = GroupId privateGroupId =
new GroupId(meta.getRaw(MSG_KEY_PRIVATE_GROUP_ID)); new GroupId(meta.getRaw(MSG_KEY_PRIVATE_GROUP_ID));
long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); long timestamp = meta.getLong(MSG_KEY_TIMESTAMP);

View File

@@ -15,7 +15,7 @@ interface SessionParser {
Role getRole(BdfDictionary d) throws FormatException; Role getRole(BdfDictionary d) throws FormatException;
boolean isSession(BdfDictionary d) throws FormatException; boolean isSession(BdfDictionary d);
Session parseSession(GroupId contactGroupId, BdfDictionary d) Session parseSession(GroupId contactGroupId, BdfDictionary d)
throws FormatException; throws FormatException;

View File

@@ -45,11 +45,11 @@ class SessionParserImpl implements SessionParser {
@Override @Override
public Role getRole(BdfDictionary d) throws FormatException { public Role getRole(BdfDictionary d) throws FormatException {
return Role.fromValue(d.getInt(SESSION_KEY_ROLE)); return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue());
} }
@Override @Override
public boolean isSession(BdfDictionary d) throws FormatException { public boolean isSession(BdfDictionary d) {
return d.getBoolean(SESSION_KEY_IS_SESSION, false); return d.getBoolean(SESSION_KEY_IS_SESSION, false);
} }
@@ -101,7 +101,7 @@ class SessionParserImpl implements SessionParser {
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {
return d.getInt(SESSION_KEY_STATE); return d.getLong(SESSION_KEY_STATE).intValue();
} }
private GroupId getPrivateGroupId(BdfDictionary d) throws FormatException { private GroupId getPrivateGroupId(BdfDictionary d) throws FormatException {

View File

@@ -64,8 +64,8 @@ abstract class MessageParserImpl<S extends Shareable>
@Override @Override
public MessageMetadata parseMetadata(BdfDictionary meta) public MessageMetadata parseMetadata(BdfDictionary meta)
throws FormatException { throws FormatException {
MessageType type = MessageType type = MessageType
MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE)); .fromValue(meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue());
GroupId shareableId = new GroupId(meta.getRaw(MSG_KEY_SHAREABLE_ID)); GroupId shareableId = new GroupId(meta.getRaw(MSG_KEY_SHAREABLE_ID));
long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); long timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
boolean local = meta.getBoolean(MSG_KEY_LOCAL); boolean local = meta.getBoolean(MSG_KEY_LOCAL);

View File

@@ -13,7 +13,7 @@ interface SessionParser {
BdfDictionary getAllSessionsQuery(); BdfDictionary getAllSessionsQuery();
boolean isSession(BdfDictionary d) throws FormatException; boolean isSession(BdfDictionary d);
Session parseSession(GroupId contactGroupId, BdfDictionary d) Session parseSession(GroupId contactGroupId, BdfDictionary d)
throws FormatException; throws FormatException;

View File

@@ -40,7 +40,7 @@ class SessionParserImpl implements SessionParser {
} }
@Override @Override
public boolean isSession(BdfDictionary d) throws FormatException { public boolean isSession(BdfDictionary d) {
return d.getBoolean(SESSION_KEY_IS_SESSION, false); return d.getBoolean(SESSION_KEY_IS_SESSION, false);
} }
@@ -54,7 +54,7 @@ class SessionParserImpl implements SessionParser {
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {
return d.getInt(SESSION_KEY_STATE); return d.getLong(SESSION_KEY_STATE).intValue();
} }
private GroupId getShareableId(BdfDictionary d) throws FormatException { private GroupId getShareableId(BdfDictionary d) throws FormatException {

View File

@@ -4,6 +4,12 @@ import org.briarproject.briar.client.MessageTrackerConstants;
interface SharingConstants { interface SharingConstants {
/**
* Metadata key for the client's local group, indicating that contact
* groups have been created for all contacts.
*/
String GROUP_KEY_SETUP = "setup";
// Message metadata keys // Message metadata keys
String MSG_KEY_MESSAGE_TYPE = "messageType"; String MSG_KEY_MESSAGE_TYPE = "messageType";
String MSG_KEY_SHAREABLE_ID = "shareableId"; String MSG_KEY_SHAREABLE_ID = "shareableId";

View File

@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager.ContactHook; import org.briarproject.bramble.api.contact.ContactManager.ContactHook;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataParser; import org.briarproject.bramble.api.data.MetadataParser;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
@@ -58,6 +59,7 @@ import static org.briarproject.briar.sharing.MessageType.ACCEPT;
import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.DECLINE;
import static org.briarproject.briar.sharing.MessageType.INVITE; import static org.briarproject.briar.sharing.MessageType.INVITE;
import static org.briarproject.briar.sharing.MessageType.LEAVE; import static org.briarproject.briar.sharing.MessageType.LEAVE;
import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_SETUP;
import static org.briarproject.briar.sharing.State.LOCAL_INVITED; import static org.briarproject.briar.sharing.State.LOCAL_INVITED;
import static org.briarproject.briar.sharing.State.LOCAL_LEFT; import static org.briarproject.briar.sharing.State.LOCAL_LEFT;
import static org.briarproject.briar.sharing.State.REMOTE_HANGING; import static org.briarproject.briar.sharing.State.REMOTE_HANGING;
@@ -106,13 +108,35 @@ abstract class SharingManagerImpl<S extends Shareable>
@Override @Override
public void onDatabaseOpened(Transaction txn) throws DbException { public void onDatabaseOpened(Transaction txn) throws DbException {
// Create a local group to indicate that we've set this client up // If the feature flag for this client was set and then cleared, we may
// have set things up for some pre-existing contacts and not others.
// If the local group exists and has GROUP_KEY_SETUP == true in its
// metadata then we've set things up for all contacts. Otherwise we
// need to check whether a contact group exists for each contact.
Group localGroup = contactGroupFactory.createLocalGroup(getClientId(), Group localGroup = contactGroupFactory.createLocalGroup(getClientId(),
getMajorVersion()); getMajorVersion());
if (db.containsGroup(txn, localGroup.getId())) return; try {
db.addGroup(txn, localGroup); if (db.containsGroup(txn, localGroup.getId())) {
// Set things up for any pre-existing contacts // If GROUP_KEY_SETUP == true then we're done
for (Contact c : db.getContacts(txn)) addingContact(txn, c); BdfDictionary meta = clientHelper
.getGroupMetadataAsDictionary(txn, localGroup.getId());
if (meta.getBoolean(GROUP_KEY_SETUP, false)) return;
} else {
db.addGroup(txn, localGroup);
}
BdfDictionary meta =
BdfDictionary.of(new BdfEntry(GROUP_KEY_SETUP, true));
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
} catch (FormatException e) {
throw new DbException(e);
}
// Set things up for any contacts that haven't already been set up
for (Contact c : db.getContacts(txn)) {
Group contactGroup = getContactGroup(c);
if (!db.containsGroup(txn, contactGroup.getId())) {
addingContact(txn, c);
}
}
} }
@Override @Override
@@ -604,9 +628,9 @@ abstract class SharingManagerImpl<S extends Shareable>
// get all sessions and their states // get all sessions and their states
Map<GroupId, DeletableSession> sessions = new HashMap<>(); Map<GroupId, DeletableSession> sessions = new HashMap<>();
for (BdfDictionary d : metadata.values()) { for (BdfDictionary d : metadata.values()) {
if (!sessionParser.isSession(d)) continue;
Session session; Session session;
try { try {
if (!sessionParser.isSession(d)) continue;
session = sessionParser.parseSession(contactGroup, d); session = sessionParser.parseSession(contactGroup, d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
@@ -668,12 +692,13 @@ abstract class SharingManagerImpl<S extends Shareable>
// assign protocol messages to their sessions // assign protocol messages to their sessions
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
// parse message metadata and skip messages not visible in UI // parse message metadata and skip messages not visible in UI
MessageMetadata m; MessageMetadata m;
try { try {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
m = messageParser.parseMetadata(d); m = messageParser.parseMetadata(d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);

View File

@@ -40,7 +40,7 @@ abstract class SharingValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getInt(0)); MessageType type = MessageType.fromValue(body.getLong(0).intValue());
switch (type) { switch (type) {
case INVITE: case INVITE:
return validateInviteMessage(m, body); return validateInviteMessage(m, body);

View File

@@ -651,7 +651,7 @@ public class GroupMessageValidatorTest extends ValidatorTestCase {
MessageType type, BdfList member, MessageType type, BdfList member,
Collection<MessageId> dependencies) throws FormatException { Collection<MessageId> dependencies) throws FormatException {
BdfDictionary d = c.getDictionary(); BdfDictionary d = c.getDictionary();
assertEquals(type.getInt(), d.getInt(KEY_TYPE).intValue()); assertEquals(type.getInt(), d.getLong(KEY_TYPE).intValue());
assertEquals(message.getTimestamp(), assertEquals(message.getTimestamp(),
d.getLong(KEY_TIMESTAMP).longValue()); d.getLong(KEY_TIMESTAMP).longValue());
assertFalse(d.getBoolean(KEY_READ)); assertFalse(d.getBoolean(KEY_READ));

Some files were not shown because too many files have changed in this diff Show More