mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-31 11:26:12 +00:00
Validate incoming Group lengths and remote delete entries if wrong.
Ignore incoming messages with bad V1 group lengths.
This commit is contained in:
@@ -261,19 +261,19 @@ public final class GroupIdTest {
|
||||
groupId.requireV2();
|
||||
}
|
||||
|
||||
@Test(expected = BadGroupIdException.class)
|
||||
public void cannot_create_v1_with_a_v2_length() throws IOException, BadGroupIdException {
|
||||
GroupId.v1(Hex.fromStringCondensed("9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e"));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void cannot_create_v1_with_a_v2_length() throws IOException {
|
||||
public void cannot_create_v1_with_a_v2_length_assert() throws IOException {
|
||||
GroupId.v1orThrow(Hex.fromStringCondensed("9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e"));
|
||||
}
|
||||
|
||||
@Test(expected = BadGroupIdException.class)
|
||||
public void cannot_create_v2_with_a_v1_length() throws IOException, BadGroupIdException {
|
||||
GroupId.v2(Hex.fromStringCondensed("000102030405060708090a0b0c0d0e0f"));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void cannot_create_v2_with_a_v1_length_assert() throws IOException {
|
||||
GroupId.v2orThrow(Hex.fromStringCondensed("000102030405060708090a0b0c0d0e0f"));
|
||||
public void cannot_create_v1_with_wrong_length() throws IOException, BadGroupIdException {
|
||||
GroupId.v1Exact(Hex.fromStringCondensed("000102030405060708090a0b0c0d0e"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -292,6 +292,22 @@ public final class GroupIdTest {
|
||||
assertTrue(v1.isV1());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1_static_factory() throws BadGroupIdException {
|
||||
GroupId.V1 v1 = GroupId.v1(new byte[]{ 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||
|
||||
assertEquals("__textsecure_group__!090a0b0c0d0e0f000102030405060708", v1.toString());
|
||||
assertTrue(v1.isV1());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void v1Exact_static_factory() throws BadGroupIdException {
|
||||
GroupId.V1 v1 = GroupId.v1Exact(new byte[]{ 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||
|
||||
assertEquals("__textsecure_group__!090a0b0c0d0e0f000102030405060708", v1.toString());
|
||||
assertTrue(v1.isV1());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parse_bytes_to_v1_via_push() throws BadGroupIdException {
|
||||
GroupId.V1 v1 = GroupId.push(new byte[]{ 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8 }).requireV1();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package org.thoughtcrime.securesms.storage;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.thoughtcrime.securesms.storage.GroupV1ConflictMerger;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper.KeyGenerator;
|
||||
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
@@ -14,10 +15,11 @@ import static org.powermock.api.mockito.PowerMockito.mock;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
import static org.thoughtcrime.securesms.testutil.TestHelpers.byteArray;
|
||||
|
||||
public class GroupV1ConflictMergerTest {
|
||||
public final class GroupV1ConflictMergerTest {
|
||||
|
||||
private static final byte[] GENERATED_KEY = byteArray(8675309);
|
||||
private static final KeyGenerator KEY_GENERATOR = mock(KeyGenerator.class);
|
||||
|
||||
private static byte[] GENERATED_KEY = byteArray(8675309);
|
||||
private static KeyGenerator KEY_GENERATOR = mock(KeyGenerator.class);
|
||||
static {
|
||||
when(KEY_GENERATOR.generate()).thenReturn(GENERATED_KEY);
|
||||
}
|
||||
@@ -78,4 +80,31 @@ public class GroupV1ConflictMergerTest {
|
||||
|
||||
assertEquals(local, merged);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void merge_excludeBadGroupId() {
|
||||
SignalGroupV1Record badRemote = new SignalGroupV1Record.Builder(byteArray(1), badGroupKey(99))
|
||||
.setBlocked(false)
|
||||
.setProfileSharingEnabled(true)
|
||||
.setArchived(true)
|
||||
.build();
|
||||
|
||||
SignalGroupV1Record goodRemote = new SignalGroupV1Record.Builder(byteArray(1), groupKey(99))
|
||||
.setBlocked(false)
|
||||
.setProfileSharingEnabled(true)
|
||||
.setArchived(true)
|
||||
.build();
|
||||
|
||||
Collection<SignalGroupV1Record> invalid = new GroupV1ConflictMerger(Collections.emptyList()).getInvalidEntries(Arrays.asList(badRemote, goodRemote));
|
||||
|
||||
assertEquals(Collections.singletonList(badRemote), invalid);
|
||||
}
|
||||
|
||||
private static byte[] groupKey(int value) {
|
||||
return byteArray(value, 16);
|
||||
}
|
||||
|
||||
private static byte[] badGroupKey(int value) {
|
||||
return byteArray(value, 32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.thoughtcrime.securesms.storage;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.signal.zkgroup.InvalidInputException;
|
||||
import org.signal.zkgroup.groups.GroupMasterKey;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper.KeyGenerator;
|
||||
import org.whispersystems.signalservice.api.storage.SignalGroupV2Record;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
@@ -15,10 +15,11 @@ import static org.powermock.api.mockito.PowerMockito.mock;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
import static org.thoughtcrime.securesms.testutil.TestHelpers.byteArray;
|
||||
|
||||
public class GroupV2ConflictMergerTest {
|
||||
public final class GroupV2ConflictMergerTest {
|
||||
|
||||
private static final byte[] GENERATED_KEY = byteArray(8675309);
|
||||
private static final KeyGenerator KEY_GENERATOR = mock(KeyGenerator.class);
|
||||
|
||||
private static byte[] GENERATED_KEY = byteArray(8675309);
|
||||
private static KeyGenerator KEY_GENERATOR = mock(KeyGenerator.class);
|
||||
static {
|
||||
when(KEY_GENERATOR.generate()).thenReturn(GENERATED_KEY);
|
||||
}
|
||||
@@ -26,20 +27,20 @@ public class GroupV2ConflictMergerTest {
|
||||
@Test
|
||||
public void merge_alwaysPreferRemote_exceptProfileSharingIsEitherOr() {
|
||||
SignalGroupV2Record remote = new SignalGroupV2Record.Builder(byteArray(1), groupKey(100))
|
||||
.setBlocked(false)
|
||||
.setProfileSharingEnabled(false)
|
||||
.setArchived(false)
|
||||
.build();
|
||||
.setBlocked(false)
|
||||
.setProfileSharingEnabled(false)
|
||||
.setArchived(false)
|
||||
.build();
|
||||
SignalGroupV2Record local = new SignalGroupV2Record.Builder(byteArray(2), groupKey(100))
|
||||
.setBlocked(true)
|
||||
.setProfileSharingEnabled(true)
|
||||
.setArchived(true)
|
||||
.build();
|
||||
.setBlocked(true)
|
||||
.setProfileSharingEnabled(true)
|
||||
.setArchived(true)
|
||||
.build();
|
||||
|
||||
SignalGroupV2Record merged = new GroupV2ConflictMerger(Collections.singletonList(local)).merge(remote, local, KEY_GENERATOR);
|
||||
|
||||
assertArrayEquals(GENERATED_KEY, merged.getId().getRaw());
|
||||
assertEquals(groupKey(100), merged.getMasterKey());
|
||||
assertArrayEquals(groupKey(100), merged.getMasterKeyBytes());
|
||||
assertFalse(merged.isBlocked());
|
||||
assertFalse(merged.isArchived());
|
||||
}
|
||||
@@ -80,11 +81,30 @@ public class GroupV2ConflictMergerTest {
|
||||
assertEquals(local, merged);
|
||||
}
|
||||
|
||||
private static GroupMasterKey groupKey(int value) {
|
||||
try {
|
||||
return new GroupMasterKey(byteArray(value, 32));
|
||||
} catch (InvalidInputException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
@Test
|
||||
public void merge_excludeBadGroupId() {
|
||||
SignalGroupV2Record badRemote = new SignalGroupV2Record.Builder(byteArray(1), badGroupKey(99))
|
||||
.setBlocked(false)
|
||||
.setProfileSharingEnabled(true)
|
||||
.setArchived(true)
|
||||
.build();
|
||||
|
||||
SignalGroupV2Record goodRemote = new SignalGroupV2Record.Builder(byteArray(1), groupKey(99))
|
||||
.setBlocked(false)
|
||||
.setProfileSharingEnabled(true)
|
||||
.setArchived(true)
|
||||
.build();
|
||||
|
||||
Collection<SignalGroupV2Record> invalid = new GroupV2ConflictMerger(Collections.emptyList()).getInvalidEntries(Arrays.asList(badRemote, goodRemote));
|
||||
|
||||
assertEquals(Collections.singletonList(badRemote), invalid);
|
||||
}
|
||||
|
||||
private static byte[] groupKey(int value) {
|
||||
return byteArray(value, 32);
|
||||
}
|
||||
|
||||
private static byte[] badGroupKey(int value) {
|
||||
return byteArray(value, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,34 @@ public final class StorageSyncHelperTest {
|
||||
assertEquals(setOf(remote1), result.getRemoteDeletes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_contact_deleteBadGv1() {
|
||||
SignalGroupV1Record remote1 = badGroupV1(1, 1, true, false);
|
||||
SignalGroupV1Record local1 = groupV1(2, 1, true, true);
|
||||
|
||||
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
|
||||
|
||||
assertTrue(result.getLocalContactInserts().isEmpty());
|
||||
assertTrue(result.getLocalContactUpdates().isEmpty());
|
||||
assertEquals(setOf(record(local1)), result.getRemoteInserts());
|
||||
assertTrue(result.getRemoteUpdates().isEmpty());
|
||||
assertEquals(setOf(remote1), result.getRemoteDeletes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_contact_deleteBadGv2() {
|
||||
SignalGroupV2Record remote1 = badGroupV2(1, 2, true, false);
|
||||
SignalGroupV2Record local1 = groupV2(2, 2, true, false);
|
||||
|
||||
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
|
||||
|
||||
assertTrue(result.getLocalContactInserts().isEmpty());
|
||||
assertTrue(result.getLocalContactUpdates().isEmpty());
|
||||
assertEquals(setOf(record(local1)), result.getRemoteInserts());
|
||||
assertTrue(result.getRemoteUpdates().isEmpty());
|
||||
assertEquals(setOf(remote1), result.getRemoteDeletes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_contact_sameAsRemote() {
|
||||
SignalContactRecord remote1 = contact(1, UUID_A, E164_A, "a");
|
||||
@@ -417,7 +445,15 @@ public final class StorageSyncHelperTest {
|
||||
boolean blocked,
|
||||
boolean profileSharing)
|
||||
{
|
||||
return new SignalGroupV1Record.Builder(byteArray(key), byteArray(groupId)).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
return new SignalGroupV1Record.Builder(byteArray(key), byteArray(groupId, 16)).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
}
|
||||
|
||||
private static SignalGroupV1Record badGroupV1(int key,
|
||||
int groupId,
|
||||
boolean blocked,
|
||||
boolean profileSharing)
|
||||
{
|
||||
return new SignalGroupV1Record.Builder(byteArray(key), byteArray(groupId, 42)).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
}
|
||||
|
||||
private static SignalGroupV2Record groupV2(int key,
|
||||
@@ -425,11 +461,15 @@ public final class StorageSyncHelperTest {
|
||||
boolean blocked,
|
||||
boolean profileSharing)
|
||||
{
|
||||
try {
|
||||
return new SignalGroupV2Record.Builder(byteArray(key), new GroupMasterKey(byteArray(groupId, 32))).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
} catch (InvalidInputException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return new SignalGroupV2Record.Builder(byteArray(key), byteArray(groupId, 32)).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
}
|
||||
|
||||
private static SignalGroupV2Record badGroupV2(int key,
|
||||
int groupId,
|
||||
boolean blocked,
|
||||
boolean profileSharing)
|
||||
{
|
||||
return new SignalGroupV2Record.Builder(byteArray(key), byteArray(groupId, 42)).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
}
|
||||
|
||||
private static <E extends SignalRecord> StorageSyncHelper.RecordUpdate<E> update(E oldRecord, E newRecord) {
|
||||
|
||||
Reference in New Issue
Block a user