diff --git a/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt b/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt index 36a476f2f..60d1966d1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt @@ -29,10 +29,9 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import com.keylesspalace.tusky.components.account.AccountActivity import com.keylesspalace.tusky.components.viewthread.ViewThreadActivity import com.keylesspalace.tusky.network.MastodonApi +import com.keylesspalace.tusky.util.looksLikeMastodonUrl import com.keylesspalace.tusky.util.openLink import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import java.net.URI -import java.net.URISyntaxException import javax.inject.Inject /** this is the base class for all activities that open links @@ -173,45 +172,6 @@ abstract class BottomSheetActivity : BaseActivity() { } } -// https://mastodon.foo.bar/@User -// https://mastodon.foo.bar/@User/43456787654678 -// https://pleroma.foo.bar/users/User -// https://pleroma.foo.bar/users/9qTHT2ANWUdXzENqC0 -// https://pleroma.foo.bar/notice/9sBHWIlwwGZi5QGlHc -// https://pleroma.foo.bar/objects/d4643c42-3ae0-4b73-b8b0-c725f5819207 -// https://friendica.foo.bar/profile/user -// https://friendica.foo.bar/display/d4643c42-3ae0-4b73-b8b0-c725f5819207 -// https://misskey.foo.bar/notes/83w6r388br (always lowercase) -// https://pixelfed.social/p/connyduck/391263492998670833 -// https://pixelfed.social/connyduck -fun looksLikeMastodonUrl(urlString: String): Boolean { - val uri: URI - try { - uri = URI(urlString) - } catch (e: URISyntaxException) { - return false - } - - if (uri.query != null || - uri.fragment != null || - uri.path == null - ) { - return false - } - - val path = uri.path - return path.matches("^/@[^/]+$".toRegex()) || - path.matches("^/@[^/]+/\\d+$".toRegex()) || - path.matches("^/users/\\w+$".toRegex()) || - path.matches("^/notice/[a-zA-Z0-9]+$".toRegex()) || - path.matches("^/objects/[-a-f0-9]+$".toRegex()) || - path.matches("^/notes/[a-z0-9]+$".toRegex()) || - path.matches("^/display/[-a-f0-9]+$".toRegex()) || - path.matches("^/profile/\\w+$".toRegex()) || - path.matches("^/p/\\w+/\\d+$".toRegex()) || - path.matches("^/\\w+$".toRegex()) -} - enum class PostLookupFallbackBehavior { OPEN_IN_BROWSER, DISPLAY_ERROR, diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt index 39489e4a0..69f84593c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt @@ -37,6 +37,8 @@ import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.HashTag import com.keylesspalace.tusky.entity.Status.Mention import com.keylesspalace.tusky.interfaces.LinkListener +import java.net.URI +import java.net.URISyntaxException fun getDomain(urlString: String?): String { val host = urlString?.toUri()?.host @@ -270,4 +272,49 @@ private fun openLinkInCustomTab(uri: Uri, context: Context) { } } +// https://mastodon.foo.bar/@User +// https://mastodon.foo.bar/@User/43456787654678 +// https://pleroma.foo.bar/users/User +// https://pleroma.foo.bar/users/9qTHT2ANWUdXzENqC0 +// https://pleroma.foo.bar/notice/9sBHWIlwwGZi5QGlHc +// https://pleroma.foo.bar/objects/d4643c42-3ae0-4b73-b8b0-c725f5819207 +// https://friendica.foo.bar/profile/user +// https://friendica.foo.bar/display/d4643c42-3ae0-4b73-b8b0-c725f5819207 +// https://misskey.foo.bar/notes/83w6r388br (always lowercase) +// https://pixelfed.social/p/connyduck/391263492998670833 +// https://pixelfed.social/connyduck +// https://gts.foo.bar/@goblin/statuses/01GH9XANCJ0TA8Y95VE9H3Y0Q2 +// https://gts.foo.bar/@goblin +// https://foo.microblog.pub/o/5b64045effd24f48a27d7059f6cb38f5 +fun looksLikeMastodonUrl(urlString: String): Boolean { + val uri: URI + try { + uri = URI(urlString) + } catch (e: URISyntaxException) { + return false + } + + if (uri.query != null || + uri.fragment != null || + uri.path == null + ) { + return false + } + + return uri.path.let { + it.matches("^/@[^/]+$".toRegex()) || + it.matches("^/@[^/]+/\\d+$".toRegex()) || + it.matches("^/users/\\w+$".toRegex()) || + it.matches("^/notice/[a-zA-Z0-9]+$".toRegex()) || + it.matches("^/objects/[-a-f0-9]+$".toRegex()) || + it.matches("^/notes/[a-z0-9]+$".toRegex()) || + it.matches("^/display/[-a-f0-9]+$".toRegex()) || + it.matches("^/profile/\\w+$".toRegex()) || + it.matches("^/p/\\w+/\\d+$".toRegex()) || + it.matches("^/\\w+$".toRegex()) || + it.matches("^/@[^/]+/statuses/[a-zA-Z0-9]+$".toRegex()) || + it.matches("^/o/[a-f0-9]+$".toRegex()) + } +} + private const val TAG = "LinkHelper" diff --git a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt index 406ce712a..66b922bd5 100644 --- a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt @@ -30,8 +30,6 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Mockito.eq import org.mockito.kotlin.doReturn @@ -109,70 +107,6 @@ class BottomSheetActivityTest { activity = FakeBottomSheetActivity(apiMock) } - @RunWith(Parameterized::class) - class UrlMatchingTests(private val url: String, private val expectedResult: Boolean) { - companion object { - @Parameterized.Parameters(name = "match_{0}") - @JvmStatic - fun data(): Iterable { - return listOf( - arrayOf("https://mastodon.foo.bar/@User", true), - arrayOf("http://mastodon.foo.bar/@abc123", true), - arrayOf("https://mastodon.foo.bar/@user/345667890345678", true), - arrayOf("https://mastodon.foo.bar/@user/3", true), - arrayOf("https://pleroma.foo.bar/users/meh3223", true), - arrayOf("https://pleroma.foo.bar/users/meh3223_bruh", true), - arrayOf("https://pleroma.foo.bar/users/2345", true), - arrayOf("https://pleroma.foo.bar/notice/9", true), - arrayOf("https://pleroma.foo.bar/notice/9345678", true), - arrayOf("https://pleroma.foo.bar/notice/wat", true), - arrayOf("https://pleroma.foo.bar/notice/9qTHT2ANWUdXzENqC0", true), - arrayOf("https://pleroma.foo.bar/objects/abcdef-123-abcd-9876543", true), - arrayOf("https://misskey.foo.bar/notes/mew", true), - arrayOf("https://misskey.foo.bar/notes/1421564653", true), - arrayOf("https://misskey.foo.bar/notes/qwer615985ddf", true), - arrayOf("https://friendica.foo.bar/profile/user", true), - arrayOf("https://friendica.foo.bar/profile/uSeR", true), - arrayOf("https://friendica.foo.bar/profile/user_user", true), - arrayOf("https://friendica.foo.bar/profile/123", true), - arrayOf("https://friendica.foo.bar/display/abcdef-123-abcd-9876543", true), - arrayOf("https://google.com/", false), - arrayOf("https://mastodon.foo.bar/@User?foo=bar", false), - arrayOf("https://mastodon.foo.bar/@User#foo", false), - arrayOf("http://mastodon.foo.bar/@", false), - arrayOf("http://mastodon.foo.bar/@/345678", false), - arrayOf("https://mastodon.foo.bar/@user/345667890345678/", false), - arrayOf("https://mastodon.foo.bar/@user/3abce", false), - arrayOf("https://pleroma.foo.bar/users/", false), - arrayOf("https://pleroma.foo.bar/users/meow/", false), - arrayOf("https://pleroma.foo.bar/users/@meow", false), - arrayOf("https://pleroma.foo.bar/user/2345", false), - arrayOf("https://pleroma.foo.bar/notices/123456", false), - arrayOf("https://pleroma.foo.bar/notice/@neverhappen/", false), - arrayOf("https://pleroma.foo.bar/object/abcdef-123-abcd-9876543", false), - arrayOf("https://pleroma.foo.bar/objects/xabcdef-123-abcd-9876543", false), - arrayOf("https://pleroma.foo.bar/objects/xabcdef-123-abcd-9876543/", false), - arrayOf("https://pleroma.foo.bar/objects/xabcdef-123-abcd_9876543", false), - arrayOf("https://friendica.foo.bar/display/xabcdef-123-abcd-9876543", false), - arrayOf("https://friendica.foo.bar/display/xabcdef-123-abcd-9876543/", false), - arrayOf("https://friendica.foo.bar/display/xabcdef-123-abcd_9876543", false), - arrayOf("https://friendica.foo.bar/profile/@mew", false), - arrayOf("https://friendica.foo.bar/profile/@mew/", false), - arrayOf("https://misskey.foo.bar/notes/@nyan", false), - arrayOf("https://misskey.foo.bar/notes/NYAN123", false), - arrayOf("https://misskey.foo.bar/notes/meow123/", false), - arrayOf("https://pixelfed.social/p/connyduck/391263492998670833", true), - arrayOf("https://pixelfed.social/connyduck", true) - ) - } - } - - @Test - fun test() { - assertEquals(expectedResult, looksLikeMastodonUrl(url)) - } - } - @Test fun beginEndSearch_setIsSearching_isSearchingAfterBegin() { activity.onBeginSearch("https://mastodon.foo.bar/@User") diff --git a/app/src/test/java/com/keylesspalace/tusky/util/LinkHelperTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/LinkHelperTest.kt index 6264d86b9..85be92dc7 100644 --- a/app/src/test/java/com/keylesspalace/tusky/util/LinkHelperTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/util/LinkHelperTest.kt @@ -12,6 +12,7 @@ import com.keylesspalace.tusky.interfaces.LinkListener import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith +import org.junit.runners.Parameterized import org.robolectric.annotation.Config @Config(sdk = [28]) @@ -308,4 +309,71 @@ class LinkHelperTest { Assert.assertFalse(markedUpContent.contains("${getDomain(tag.url)})")) } } + + @RunWith(Parameterized::class) + class UrlMatchingTests(private val url: String, private val expectedResult: Boolean) { + companion object { + @Parameterized.Parameters(name = "match_{0}") + @JvmStatic + fun data(): Iterable { + return listOf( + arrayOf("https://mastodon.foo.bar/@User", true), + arrayOf("http://mastodon.foo.bar/@abc123", true), + arrayOf("https://mastodon.foo.bar/@user/345667890345678", true), + arrayOf("https://mastodon.foo.bar/@user/3", true), + arrayOf("https://pleroma.foo.bar/users/meh3223", true), + arrayOf("https://pleroma.foo.bar/users/meh3223_bruh", true), + arrayOf("https://pleroma.foo.bar/users/2345", true), + arrayOf("https://pleroma.foo.bar/notice/9", true), + arrayOf("https://pleroma.foo.bar/notice/9345678", true), + arrayOf("https://pleroma.foo.bar/notice/wat", true), + arrayOf("https://pleroma.foo.bar/notice/9qTHT2ANWUdXzENqC0", true), + arrayOf("https://pleroma.foo.bar/objects/abcdef-123-abcd-9876543", true), + arrayOf("https://misskey.foo.bar/notes/mew", true), + arrayOf("https://misskey.foo.bar/notes/1421564653", true), + arrayOf("https://misskey.foo.bar/notes/qwer615985ddf", true), + arrayOf("https://friendica.foo.bar/profile/user", true), + arrayOf("https://friendica.foo.bar/profile/uSeR", true), + arrayOf("https://friendica.foo.bar/profile/user_user", true), + arrayOf("https://friendica.foo.bar/profile/123", true), + arrayOf("https://friendica.foo.bar/display/abcdef-123-abcd-9876543", true), + arrayOf("https://google.com/", false), + arrayOf("https://mastodon.foo.bar/@User?foo=bar", false), + arrayOf("https://mastodon.foo.bar/@User#foo", false), + arrayOf("http://mastodon.foo.bar/@", false), + arrayOf("http://mastodon.foo.bar/@/345678", false), + arrayOf("https://mastodon.foo.bar/@user/345667890345678/", false), + arrayOf("https://mastodon.foo.bar/@user/3abce", false), + arrayOf("https://pleroma.foo.bar/users/", false), + arrayOf("https://pleroma.foo.bar/users/meow/", false), + arrayOf("https://pleroma.foo.bar/users/@meow", false), + arrayOf("https://pleroma.foo.bar/user/2345", false), + arrayOf("https://pleroma.foo.bar/notices/123456", false), + arrayOf("https://pleroma.foo.bar/notice/@neverhappen/", false), + arrayOf("https://pleroma.foo.bar/object/abcdef-123-abcd-9876543", false), + arrayOf("https://pleroma.foo.bar/objects/xabcdef-123-abcd-9876543", false), + arrayOf("https://pleroma.foo.bar/objects/xabcdef-123-abcd-9876543/", false), + arrayOf("https://pleroma.foo.bar/objects/xabcdef-123-abcd_9876543", false), + arrayOf("https://friendica.foo.bar/display/xabcdef-123-abcd-9876543", false), + arrayOf("https://friendica.foo.bar/display/xabcdef-123-abcd-9876543/", false), + arrayOf("https://friendica.foo.bar/display/xabcdef-123-abcd_9876543", false), + arrayOf("https://friendica.foo.bar/profile/@mew", false), + arrayOf("https://friendica.foo.bar/profile/@mew/", false), + arrayOf("https://misskey.foo.bar/notes/@nyan", false), + arrayOf("https://misskey.foo.bar/notes/NYAN123", false), + arrayOf("https://misskey.foo.bar/notes/meow123/", false), + arrayOf("https://pixelfed.social/p/connyduck/391263492998670833", true), + arrayOf("https://pixelfed.social/connyduck", true), + arrayOf("https://gts.foo.bar/@goblin/statuses/01GH9XANCJ0TA8Y95VE9H3Y0Q2", true), + arrayOf("https://gts.foo.bar/@goblin", true), + arrayOf("https://foo.microblog.pub/o/5b64045effd24f48a27d7059f6cb38f5", true), + ) + } + } + + @Test + fun test() { + Assert.assertEquals(expectedResult, looksLikeMastodonUrl(url)) + } + } }