diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4e50e84d16..1221f99d41 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -223,6 +223,14 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java
index fa62526160..6f708bec7b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/invitesandrequests/joining/GroupJoinBottomSheetDialogFragment.java
@@ -195,7 +195,7 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
private GroupInviteLinkUrl getGroupInviteLinkUrl() {
try {
//noinspection ConstantConditions
- return GroupInviteLinkUrl.fromUrl(requireArguments().getString(ARG_GROUP_INVITE_LINK_URL));
+ return GroupInviteLinkUrl.fromUri(requireArguments().getString(ARG_GROUP_INVITE_LINK_URL));
} catch (GroupInviteLinkUrl.InvalidGroupLinkException | GroupInviteLinkUrl.UnknownGroupLinkVersionException e) {
throw new AssertionError();
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java
index 7995fe9ed5..40ee561b9d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl.java
@@ -12,8 +12,8 @@ import org.signal.zkgroup.groups.GroupMasterKey;
import org.whispersystems.util.Base64UrlSafe;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
+import java.net.URISyntaxException;
public final class GroupInviteLinkUrl {
@@ -38,24 +38,24 @@ public final class GroupInviteLinkUrl {
* @return null iff not a group url.
* @throws InvalidGroupLinkException If group url, but cannot be parsed.
*/
- public static @Nullable GroupInviteLinkUrl fromUrl(@NonNull String urlString)
+ public static @Nullable GroupInviteLinkUrl fromUri(@NonNull String urlString)
throws InvalidGroupLinkException, UnknownGroupLinkVersionException
{
- URL url = getGroupUrl(urlString);
+ URI uri = getGroupUrl(urlString);
- if (url == null) {
+ if (uri == null) {
return null;
}
try {
- if (!"/".equals(url.getPath()) && url.getPath().length() > 0) {
- throw new InvalidGroupLinkException("No path was expected in url");
+ if (!"/".equals(uri.getPath()) && uri.getPath().length() > 0) {
+ throw new InvalidGroupLinkException("No path was expected in uri");
}
- String encoding = url.getRef();
+ String encoding = uri.getFragment();
if (encoding == null || encoding.length() == 0) {
- throw new InvalidGroupLinkException("No reference was in the url");
+ throw new InvalidGroupLinkException("No reference was in the uri");
}
byte[] bytes = Base64UrlSafe.decodePaddingAgnostic(encoding);
@@ -78,16 +78,23 @@ public final class GroupInviteLinkUrl {
}
/**
- * @return {@link URL} if the host name matches.
+ * @return {@link URI} if the host name matches.
*/
- private static URL getGroupUrl(@NonNull String urlString) {
+ private static URI getGroupUrl(@NonNull String urlString) {
try {
- URL url = new URL(urlString);
+ URI url = new URI(urlString);
+
+ if (!"https".equalsIgnoreCase(url.getScheme()) &&
+ !"sgnl".equalsIgnoreCase(url.getScheme()))
+ {
+ return null;
+ }
return GROUP_URL_HOST.equalsIgnoreCase(url.getHost())
? url
: null;
- } catch (MalformedURLException e) {
+
+ } catch (URISyntaxException e) {
return null;
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java b/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java
index 136fb581a8..d5e667caad 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java
@@ -252,7 +252,7 @@ public class LinkPreviewRepository {
{
SignalExecutors.UNBOUNDED.execute(() -> {
try {
- GroupInviteLinkUrl groupInviteLinkUrl = GroupInviteLinkUrl.fromUrl(groupUrl);
+ GroupInviteLinkUrl groupInviteLinkUrl = GroupInviteLinkUrl.fromUri(groupUrl);
if (groupInviteLinkUrl == null) {
throw new AssertionError();
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
index 511ae27dff..4fb9460d05 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
@@ -165,7 +165,7 @@ public class CommunicationActions {
*/
public static boolean handlePotentialGroupLinkUrl(@NonNull FragmentActivity activity, @NonNull String potentialGroupLinkUrl) {
try {
- GroupInviteLinkUrl groupInviteLinkUrl = GroupInviteLinkUrl.fromUrl(potentialGroupLinkUrl);
+ GroupInviteLinkUrl groupInviteLinkUrl = GroupInviteLinkUrl.fromUri(potentialGroupLinkUrl);
if (groupInviteLinkUrl == null) {
return false;
diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrlTest.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrlTest.java
index 14ca75cc11..a48797edfa 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrlTest.java
+++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrlTest.java
@@ -37,7 +37,11 @@ public final class GroupInviteLinkUrlTest {
givenGroup().withMasterKey("00f7e0c2a71ab064cc3ced4c04f08d7b7ef4b84b2c2206f69833be6cfe34df80")
.andPassword("9b")
- .expectUrl("https://signal.group/#CiUKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEgGb")
+ .expectUrl("https://signal.group/#CiUKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEgGb"),
+
+ givenGroup().withMasterKey("2ca23c04d7cf60fe04039ae76d1912202c2a463d345d9cd48cf27f260dd37f6f")
+ .andPassword("2734457c02ce51da71ad0b62f3c222f7")
+ .expectUrl("sgnl://signal.group/#CjQKICyiPATXz2D-BAOa520ZEiAsKkY9NF2c1IzyfyYN039vEhAnNEV8As5R2nGtC2LzwiL3")
);
}
@@ -49,27 +53,33 @@ public final class GroupInviteLinkUrlTest {
@Test
public void can_extract_group_master_key_from_url() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertEquals(groupMasterKey, GroupInviteLinkUrl.fromUrl(expectedUrl).getGroupMasterKey());
+ assertEquals(groupMasterKey, GroupInviteLinkUrl.fromUri(expectedUrl).getGroupMasterKey());
}
@Test
public void can_extract_group_master_key_from_url_padded() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertEquals(groupMasterKey, GroupInviteLinkUrl.fromUrl(expectedUrl + "=").getGroupMasterKey());
+ assertEquals(groupMasterKey, GroupInviteLinkUrl.fromUri(expectedUrl + "=").getGroupMasterKey());
}
@Test
public void can_extract_password_from_url() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertEquals(password, GroupInviteLinkUrl.fromUrl(expectedUrl).getPassword());
+ assertEquals(password, GroupInviteLinkUrl.fromUri(expectedUrl).getPassword());
}
@Test
public void can_extract_password_from_url_padded() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertEquals(password, GroupInviteLinkUrl.fromUrl(expectedUrl + "=").getPassword());
+ assertEquals(password, GroupInviteLinkUrl.fromUri(expectedUrl + "=").getPassword());
}
@Test
public void can_reconstruct_url() {
- assertEquals(expectedUrl, GroupInviteLinkUrl.createUrl(groupMasterKey, password));
+ String urlToCompare = expectedUrl;
+
+ if (urlToCompare.startsWith("sgnl")) {
+ urlToCompare = urlToCompare.replace("sgnl", "https");
+ }
+
+ assertEquals(urlToCompare, GroupInviteLinkUrl.createUrl(groupMasterKey, password));
}
private static TestBuilder givenGroup() {
diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java
index f1b327094b..c6f079f1b5 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java
+++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/GroupInviteLinkUrl_InvalidGroupLinkException_Test.java
@@ -8,7 +8,6 @@ import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Test;
import org.signal.storageservice.protos.groups.GroupInviteLink;
import org.signal.zkgroup.InvalidInputException;
-import org.signal.zkgroup.groups.GroupMasterKey;
import org.whispersystems.util.Base64UrlSafe;
import org.thoughtcrime.securesms.util.Util;
@@ -21,50 +20,55 @@ public final class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
@Test
public void empty_string() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertNull(GroupInviteLinkUrl.fromUrl(""));
+ assertNull(GroupInviteLinkUrl.fromUri(""));
}
@Test
public void not_a_url_string() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertNull(GroupInviteLinkUrl.fromUrl("abc"));
+ assertNull(GroupInviteLinkUrl.fromUri("abc"));
}
@Test
public void wrong_host() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
- assertNull(GroupInviteLinkUrl.fromUrl("https://x.signal.org/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6OHTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"));
+ assertNull(GroupInviteLinkUrl.fromUri("https://x.signal.org/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"));
+ }
+
+ @Test
+ public void wrong_scheme() throws GroupInviteLinkUrl.InvalidGroupLinkException, GroupInviteLinkUrl.UnknownGroupLinkVersionException {
+ assertNull(GroupInviteLinkUrl.fromUri("http://signal.group/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"));
}
@Test
public void has_path() {
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl("https://signal.group/not_expected/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6OHTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/not_expected/#CjQKIAD34MKnGrBkzDztTATwjXt-9LhLLCIG9pgzvmz-NN-AEhCbwyTuxDfP2mrluK779H7o"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
- .hasMessage("No path was expected in url");
+ .hasMessage("No path was expected in uri");
}
@Test
public void missing_ref() {
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl("https://signal.group/"))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
- .hasMessage("No reference was in the url");
+ .hasMessage("No reference was in the uri");
}
@Test
public void empty_ref() {
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl("https://signal.group/#"))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
- .hasMessage("No reference was in the url");
+ .hasMessage("No reference was in the uri");
}
@Test
public void bad_base64() {
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCX;mwVi31USVY"))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCX;mwVi31USVY"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(IOException.class);
}
@Test
public void bad_protobuf() {
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri("https://signal.group/#CAESNAogpQEzURH6BON1bCS264cmTi37Yi6HTOReXZUEHdsBIgSEPCLfiL7k4wCXmwVi31USVY"))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(InvalidProtocolBufferException.class);
}
@@ -73,7 +77,7 @@ public final class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
public void version_999_url() {
String url = "https://signal.group/#uj4zCiDMSxlNUvF4bQ3z3fYzGyZTFbJ1xEqWbPE3uZSD8bjOrxIP8NxV-0GUz3jpxMLR1rN3";
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl(url))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri(url))
.isInstanceOf(GroupInviteLinkUrl.UnknownGroupLinkVersionException.class)
.hasMessage("Url contains no known group link content");
}
@@ -87,7 +91,7 @@ public final class GroupInviteLinkUrl_InvalidGroupLinkException_Test {
String url = "https://signal.group/#" + encoding;
- assertThatThrownBy(() -> GroupInviteLinkUrl.fromUrl(url))
+ assertThatThrownBy(() -> GroupInviteLinkUrl.fromUri(url))
.isInstanceOf(GroupInviteLinkUrl.InvalidGroupLinkException.class)
.hasCauseExactlyInstanceOf(InvalidInputException.class);
}