New GV2 internal prefix and scrubber.
This commit is contained in:
parent
456857bbbd
commit
ff28d72db6
4 changed files with 61 additions and 30 deletions
|
@ -14,11 +14,12 @@ import java.security.SecureRandom;
|
||||||
|
|
||||||
public abstract class GroupId {
|
public abstract class GroupId {
|
||||||
|
|
||||||
private static final String ENCODED_SIGNAL_GROUP_PREFIX = "__textsecure_group__!";
|
private static final String ENCODED_SIGNAL_GROUP_V1_PREFIX = "__textsecure_group__!";
|
||||||
private static final String ENCODED_MMS_GROUP_PREFIX = "__signal_mms_group__!";
|
private static final String ENCODED_SIGNAL_GROUP_V2_PREFIX = "__signal_group__v2__!";
|
||||||
private static final int MMS_BYTE_LENGTH = 16;
|
private static final String ENCODED_MMS_GROUP_PREFIX = "__signal_mms_group__!";
|
||||||
private static final int V1_MMS_BYTE_LENGTH = 16;
|
private static final int MMS_BYTE_LENGTH = 16;
|
||||||
private static final int V2_BYTE_LENGTH = GroupIdentifier.SIZE;
|
private static final int V1_MMS_BYTE_LENGTH = 16;
|
||||||
|
private static final int V2_BYTE_LENGTH = GroupIdentifier.SIZE;
|
||||||
|
|
||||||
private final String encodedId;
|
private final String encodedId;
|
||||||
|
|
||||||
|
@ -106,7 +107,11 @@ public abstract class GroupId {
|
||||||
|
|
||||||
byte[] bytes = extractDecodedId(encodedGroupId);
|
byte[] bytes = extractDecodedId(encodedGroupId);
|
||||||
|
|
||||||
return encodedGroupId.startsWith(ENCODED_MMS_GROUP_PREFIX) ? mms(bytes) : push(bytes);
|
if (encodedGroupId.startsWith(ENCODED_SIGNAL_GROUP_V2_PREFIX)) return v2(bytes);
|
||||||
|
else if (encodedGroupId.startsWith(ENCODED_SIGNAL_GROUP_V1_PREFIX)) return v1(bytes);
|
||||||
|
else if (encodedGroupId.startsWith(ENCODED_MMS_GROUP_PREFIX)) return mms(bytes);
|
||||||
|
|
||||||
|
throw new BadGroupIdException();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new BadGroupIdException(e);
|
throw new BadGroupIdException(e);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +134,9 @@ public abstract class GroupId {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEncodedGroup(@NonNull String groupId) {
|
public static boolean isEncodedGroup(@NonNull String groupId) {
|
||||||
return groupId.startsWith(ENCODED_SIGNAL_GROUP_PREFIX) || groupId.startsWith(ENCODED_MMS_GROUP_PREFIX);
|
return groupId.startsWith(ENCODED_SIGNAL_GROUP_V2_PREFIX) ||
|
||||||
|
groupId.startsWith(ENCODED_SIGNAL_GROUP_V1_PREFIX) ||
|
||||||
|
groupId.startsWith(ENCODED_MMS_GROUP_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] extractDecodedId(@NonNull String encodedGroupId) throws IOException {
|
private static byte[] extractDecodedId(@NonNull String encodedGroupId) throws IOException {
|
||||||
|
@ -220,8 +227,8 @@ public abstract class GroupId {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class Push extends GroupId {
|
public static abstract class Push extends GroupId {
|
||||||
private Push(@NonNull byte[] bytes) {
|
private Push(@NonNull String prefix, @NonNull byte[] bytes) {
|
||||||
super(ENCODED_SIGNAL_GROUP_PREFIX, bytes);
|
super(prefix, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -238,7 +245,7 @@ public abstract class GroupId {
|
||||||
public static final class V1 extends GroupId.Push {
|
public static final class V1 extends GroupId.Push {
|
||||||
|
|
||||||
private V1(@NonNull byte[] bytes) {
|
private V1(@NonNull byte[] bytes) {
|
||||||
super(bytes);
|
super(ENCODED_SIGNAL_GROUP_V1_PREFIX, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -255,7 +262,7 @@ public abstract class GroupId {
|
||||||
public static final class V2 extends GroupId.Push {
|
public static final class V2 extends GroupId.Push {
|
||||||
|
|
||||||
private V2(@NonNull byte[] bytes) {
|
private V2(@NonNull byte[] bytes) {
|
||||||
super(bytes);
|
super(ENCODED_SIGNAL_GROUP_V2_PREFIX, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
package org.thoughtcrime.securesms.logsubmit.util;
|
package org.thoughtcrime.securesms.logsubmit.util;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -49,8 +47,14 @@ public final class Scrubber {
|
||||||
/**
|
/**
|
||||||
* The middle group will be censored.
|
* The middle group will be censored.
|
||||||
*/
|
*/
|
||||||
private static final Pattern GROUP_ID_PATTERN = Pattern.compile("(__)(textsecure_group__![^\\s]+)([^\\s]{2})");
|
private static final Pattern GROUP_ID_V1_PATTERN = Pattern.compile("(__)(textsecure_group__![^\\s]+)([^\\s]{2})");
|
||||||
private static final String GROUP_ID_CENSOR = "...group...";
|
private static final String GROUP_ID_V1_CENSOR = "...group...";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The middle group will be censored.
|
||||||
|
*/
|
||||||
|
private static final Pattern GROUP_ID_V2_PATTERN = Pattern.compile("(__)(signal_group__v2__![^\\s]+)([^\\s]{2})");
|
||||||
|
private static final String GROUP_ID_V2_CENSOR = "...group_v2...";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The middle group will be censored.
|
* The middle group will be censored.
|
||||||
|
@ -62,7 +66,8 @@ public final class Scrubber {
|
||||||
|
|
||||||
in = scrubE164(in);
|
in = scrubE164(in);
|
||||||
in = scrubEmail(in);
|
in = scrubEmail(in);
|
||||||
in = scrubGroups(in);
|
in = scrubGroupsV1(in);
|
||||||
|
in = scrubGroupsV2(in);
|
||||||
in = scrubUuids(in);
|
in = scrubUuids(in);
|
||||||
|
|
||||||
return in;
|
return in;
|
||||||
|
@ -83,11 +88,19 @@ public final class Scrubber {
|
||||||
.append(EMAIL_CENSOR));
|
.append(EMAIL_CENSOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CharSequence scrubGroups(@NonNull CharSequence in) {
|
private static CharSequence scrubGroupsV1(@NonNull CharSequence in) {
|
||||||
return scrub(in,
|
return scrub(in,
|
||||||
GROUP_ID_PATTERN,
|
GROUP_ID_V1_PATTERN,
|
||||||
(matcher, output) -> output.append(matcher.group(1))
|
(matcher, output) -> output.append(matcher.group(1))
|
||||||
.append(GROUP_ID_CENSOR)
|
.append(GROUP_ID_V1_CENSOR)
|
||||||
|
.append(matcher.group(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CharSequence scrubGroupsV2(@NonNull CharSequence in) {
|
||||||
|
return scrub(in,
|
||||||
|
GROUP_ID_V2_PATTERN,
|
||||||
|
(matcher, output) -> output.append(matcher.group(1))
|
||||||
|
.append(GROUP_ID_V2_CENSOR)
|
||||||
.append(matcher.group(3)));
|
.append(matcher.group(3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ public final class GroupIdTest {
|
||||||
public void can_create_for_gv2_from_GroupIdentifier() throws IOException, InvalidInputException {
|
public void can_create_for_gv2_from_GroupIdentifier() throws IOException, InvalidInputException {
|
||||||
GroupId.V2 groupId = GroupId.v2(new GroupIdentifier(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")));
|
GroupId.V2 groupId = GroupId.v2(new GroupIdentifier(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")));
|
||||||
|
|
||||||
assertEquals("__textsecure_group__!0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", groupId.toString());
|
assertEquals("__signal_group__v2__!0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", groupId.toString());
|
||||||
assertFalse(groupId.isMms());
|
assertFalse(groupId.isMms());
|
||||||
assertFalse(groupId.isV1());
|
assertFalse(groupId.isV1());
|
||||||
assertTrue(groupId.isV2());
|
assertTrue(groupId.isV2());
|
||||||
|
@ -58,7 +58,7 @@ public final class GroupIdTest {
|
||||||
|
|
||||||
GroupId.V2 groupId = GroupId.v2(new GroupMasterKey(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")));
|
GroupId.V2 groupId = GroupId.v2(new GroupMasterKey(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")));
|
||||||
|
|
||||||
assertEquals("__textsecure_group__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e", groupId.toString());
|
assertEquals("__signal_group__v2__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e", groupId.toString());
|
||||||
assertFalse(groupId.isMms());
|
assertFalse(groupId.isMms());
|
||||||
assertFalse(groupId.isV1());
|
assertFalse(groupId.isV1());
|
||||||
assertTrue(groupId.isV2());
|
assertTrue(groupId.isV2());
|
||||||
|
@ -67,9 +67,9 @@ public final class GroupIdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void can_parse_gv2() throws IOException {
|
public void can_parse_gv2() throws IOException {
|
||||||
GroupId groupId = GroupId.parseOrThrow("__textsecure_group__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e");
|
GroupId groupId = GroupId.parseOrThrow("__signal_group__v2__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e");
|
||||||
|
|
||||||
assertEquals("__textsecure_group__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e", groupId.toString());
|
assertEquals("__signal_group__v2__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e", groupId.toString());
|
||||||
assertArrayEquals(Hex.fromStringCondensed("9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e"), groupId.getDecodedId());
|
assertArrayEquals(Hex.fromStringCondensed("9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e"), groupId.getDecodedId());
|
||||||
assertFalse(groupId.isMms());
|
assertFalse(groupId.isMms());
|
||||||
assertFalse(groupId.isV1());
|
assertFalse(groupId.isV1());
|
||||||
|
@ -145,6 +145,11 @@ public final class GroupIdTest {
|
||||||
GroupId.parseOrThrow("__textsecure_group__!0001020305060708090b0c0d0e0fODD_HEX");
|
GroupId.parseOrThrow("__textsecure_group__!0001020305060708090b0c0d0e0fODD_HEX");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = BadGroupIdException.class)
|
||||||
|
public void bad_encoding__gv2_prefix_with_wrong_length() throws BadGroupIdException {
|
||||||
|
GroupId.parse("__signal_group__v2__!000102030405060708090a0b0c0d0e0f");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void get_bytes() {
|
public void get_bytes() {
|
||||||
byte[] bytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
byte[] bytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||||
|
@ -212,7 +217,7 @@ public final class GroupIdTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void require_v2_and_push() {
|
public void require_v2_and_push() {
|
||||||
GroupId groupId = GroupId.parseOrThrow("__textsecure_group__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e");
|
GroupId groupId = GroupId.parseOrThrow("__signal_group__v2__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e");
|
||||||
|
|
||||||
GroupId.V2 v2 = groupId.requireV2();
|
GroupId.V2 v2 = groupId.requireV2();
|
||||||
GroupId.Push push = groupId.requirePush();
|
GroupId.Push push = groupId.requirePush();
|
||||||
|
@ -244,7 +249,7 @@ public final class GroupIdTest {
|
||||||
|
|
||||||
@Test(expected = AssertionError.class)
|
@Test(expected = AssertionError.class)
|
||||||
public void cannot_require_v1_of_v2() throws BadGroupIdException {
|
public void cannot_require_v1_of_v2() throws BadGroupIdException {
|
||||||
GroupId groupId = GroupId.parse("__textsecure_group__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e");
|
GroupId groupId = GroupId.parse("__signal_group__v2__!9f475f59b2518bff6df22e820803f0e3585bd99e686fa7e7fbfc2f92fd5d953e");
|
||||||
|
|
||||||
groupId.requireV1();
|
groupId.requireV1();
|
||||||
}
|
}
|
||||||
|
@ -298,6 +303,6 @@ public final class GroupIdTest {
|
||||||
public void parse_bytes_to_v2_via_by_push() throws BadGroupIdException {
|
public void parse_bytes_to_v2_via_by_push() throws BadGroupIdException {
|
||||||
GroupId.V2 v2 = GroupId.push(new byte[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }).requireV2();
|
GroupId.V2 v2 = GroupId.push(new byte[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }).requireV2();
|
||||||
|
|
||||||
assertEquals("__textsecure_group__!000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", v2.toString());
|
assertEquals("__signal_group__v2__!000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", v2.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,11 +58,17 @@ public final class ScrubberTest {
|
||||||
{ "An email and a number abc@def.com +155556789012345",
|
{ "An email and a number abc@def.com +155556789012345",
|
||||||
"An email and a number a...@... +*************45" },
|
"An email and a number a...@... +*************45" },
|
||||||
|
|
||||||
{ "__textsecure_group__!abcdefg1234567890",
|
{ "__textsecure_group__!000102030405060708090a0b0c0d0e0f",
|
||||||
"__...group...90" },
|
"__...group...0f" },
|
||||||
|
|
||||||
{ "A group id __textsecure_group__!abcdefg0987654321 surrounded with text",
|
{ "A group id __textsecure_group__!000102030405060708090a0b0c0d0e1a surrounded with text",
|
||||||
"A group id __...group...21 surrounded with text" },
|
"A group id __...group...1a surrounded with text" },
|
||||||
|
|
||||||
|
{ "__signal_group__v2__!0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
|
"__...group_v2...ef" },
|
||||||
|
|
||||||
|
{ "A group v2 id __signal_group__v2__!23456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01 surrounded with text",
|
||||||
|
"A group v2 id __...group_v2...01 surrounded with text" },
|
||||||
|
|
||||||
{ "a37cb654-c9e0-4c1e-93df-3d11ca3c97f4",
|
{ "a37cb654-c9e0-4c1e-93df-3d11ca3c97f4",
|
||||||
"********-****-****-****-**********f4" },
|
"********-****-****-****-**********f4" },
|
||||||
|
|
Loading…
Add table
Reference in a new issue