Don't linkify invalid links

Amolith created

Change summary

src/main/java/de/gultsch/common/Linkify.java     | 14 ++++++
src/test/java/de/gultsch/common/LinkifyTest.java | 37 ++++++++++++++++++
2 files changed, 51 insertions(+)

Detailed changes

src/main/java/de/gultsch/common/Linkify.java 🔗

@@ -45,6 +45,8 @@ import eu.siacs.conversations.entities.ListItem;
 import eu.siacs.conversations.utils.StylingHelper;
 import eu.siacs.conversations.utils.XmppUri;
 import eu.siacs.conversations.xmpp.Jid;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -59,6 +61,9 @@ public class Linkify {
         if (scheme == null) {
             return false;
         }
+        if (!isValidUri(match)) {
+            return false;
+        }
         return switch (scheme) {
             case "tel" -> Patterns.URI_TEL.matcher(match).matches();
             case "http", "https" -> Patterns.URI_HTTP.matcher(match).matches();
@@ -77,6 +82,15 @@ public class Linkify {
         };
     }
 
+    private static boolean isValidUri(final String match) {
+        try {
+            new URI(match);
+            return true;
+        } catch (final URISyntaxException e) {
+            return false;
+        }
+    }
+
     public static void addLinks(final Spannable body) {
         android.text.util.Linkify.addLinks(body, Patterns.URI_GENERIC, null, MATCH_FILTER, null);
     }

src/test/java/de/gultsch/common/LinkifyTest.java 🔗

@@ -0,0 +1,37 @@
+package de.gultsch.common;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LinkifyTest {
+
+    @Test
+    public void malformedEscapeIsRejected() {
+        final var links = Linkify.getLinks("https://example.com/?x=%");
+
+        Assert.assertTrue(links.isEmpty());
+    }
+
+    @Test
+    public void validEscapesStillProduceLinks() {
+        final var links = Linkify.getLinks("https://example.com/?x=%20");
+
+        Assert.assertEquals(1, links.size());
+        Assert.assertEquals("https://example.com/?x=%20", links.get(0).getRaw());
+    }
+
+    @Test
+    public void ipv6HostsStillProduceLinks() {
+        final var links = Linkify.getLinks("http://[::1]/foo");
+
+        Assert.assertEquals(1, links.size());
+        Assert.assertEquals("http://[::1]/foo", links.get(0).getRaw());
+    }
+
+    @Test
+    public void bracketsInPathAreRejected() {
+        final var links = Linkify.getLinks("http://example.com/foo[bar]");
+
+        Assert.assertTrue(links.isEmpty());
+    }
+}