diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/start/NewConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/start/NewConversationFragment.kt index 7b666be56f..38eddddeaf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/start/NewConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/start/NewConversationFragment.kt @@ -46,7 +46,7 @@ class NewConversationFragment : BottomSheetDialogFragment(), NewConversationDele val bottomSheetDialog = it as BottomSheetDialog val parentLayout = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet) - parentLayout?.let { it -> + parentLayout?.let { val behaviour = BottomSheetBehavior.from(it) val layoutParams = it.layoutParams layoutParams.height = defaultPeekHeight diff --git a/app/src/main/java/org/thoughtcrime/securesms/dms/NewMessageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/dms/NewMessageFragment.kt index 74e2cac4c8..e4859cc71f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dms/NewMessageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dms/NewMessageFragment.kt @@ -60,8 +60,12 @@ class NewMessageFragment : Fragment() { } private fun createPrivateChatIfPossible(onsNameOrPublicKey: String) { - if (PublicKeyValidation.isValid(onsNameOrPublicKey)) { - createPrivateChat(onsNameOrPublicKey) + if (PublicKeyValidation.isValid(onsNameOrPublicKey, isPrefixRequired = false)) { + if (PublicKeyValidation.hasValidPrefix(onsNameOrPublicKey)) { + createPrivateChat(onsNameOrPublicKey) + } else { + Toast.makeText(requireContext(), R.string.accountIdErrorInvalid, Toast.LENGTH_SHORT).show() + } } else { // This could be an ONS name showLoader() @@ -70,9 +74,9 @@ class NewMessageFragment : Fragment() { createPrivateChat(hexEncodedPublicKey) }.failUi { exception -> hideLoader() - var message = getString(R.string.fragment_enter_public_key_error_message) - exception.localizedMessage?.let { - message = it + val message = when (exception) { + is SnodeAPI.Error.Generic -> "We couldn’t recognize this ONS. Please check and try again." + else -> exception.localizedMessage ?: getString(R.string.fragment_enter_public_key_error_message) } Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() } @@ -81,12 +85,11 @@ class NewMessageFragment : Fragment() { private fun createPrivateChat(hexEncodedPublicKey: String) { val recipient = Recipient.from(requireContext(), Address.fromSerialized(hexEncodedPublicKey), false) - val intent = Intent(requireContext(), ConversationActivityV2::class.java) - intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address) - intent.setDataAndType(requireActivity().intent.data, requireActivity().intent.type) - val existingThread = DatabaseComponent.get(requireContext()).threadDatabase().getThreadIdIfExistsFor(recipient) - intent.putExtra(ConversationActivityV2.THREAD_ID, existingThread) - requireContext().startActivity(intent) + Intent(requireContext(), ConversationActivityV2::class.java).apply { + putExtra(ConversationActivityV2.ADDRESS, recipient.address) + setDataAndType(requireActivity().intent.data, requireActivity().intent.type) + putExtra(ConversationActivityV2.THREAD_ID, DatabaseComponent.get(requireContext()).threadDatabase().getThreadIdIfExistsFor(recipient)) + }.let(requireContext()::startActivity) delegate.onDialogClosePressed() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5b4a7edeed..194fe768ed 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1081,4 +1081,5 @@ Load Account Camera Permission permanently denied. Configure in settings. Enter your recovery password to load your account. If you haven\'t saved it, you can find it in your app settings. + This Account ID is invalid. Please check and try again. diff --git a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt index 4064aba62d..39b6704098 100644 --- a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt @@ -91,7 +91,7 @@ object SnodeAPI { const val useTestnet = false // Error - internal sealed class Error(val description: String) : Exception(description) { + sealed class Error(val description: String) : Exception(description) { object Generic : Error("An error occurred.") object ClockOutOfSync : Error("Your clock is out of sync with the Service Node network.") object NoKeyPair : Error("Missing user key pair.") diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt b/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt index 26c62ba50d..a5665cd4fc 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt @@ -1,7 +1,7 @@ package org.session.libsignal.utilities enum class IdPrefix(val value: String) { - STANDARD("05"), BLINDED("15"), UN_BLINDED("00"), BLINDEDV2("25"); + STANDARD("05"), BLINDED("15"), UN_BLINDED("00"), BLINDEDV2("25"), GROUP("03"); fun isBlinded() = value == BLINDED.value || value == BLINDEDV2.value @@ -11,6 +11,7 @@ enum class IdPrefix(val value: String) { BLINDED.value -> BLINDED BLINDEDV2.value -> BLINDEDV2 UN_BLINDED.value -> UN_BLINDED + GROUP.value -> GROUP else -> null } } diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/Validation.kt b/libsignal/src/main/java/org/session/libsignal/utilities/Validation.kt index a9d38956bb..d0453fc140 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/Validation.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/Validation.kt @@ -1,18 +1,11 @@ package org.session.libsignal.utilities object PublicKeyValidation { + private val HEX_CHARACTERS = "0123456789ABCDEF".toSet() + private val INVALID_PREFIXES = setOf(IdPrefix.GROUP, IdPrefix.BLINDED, IdPrefix.BLINDEDV2) - @JvmStatic - fun isValid(candidate: String): Boolean { - return isValid(candidate, 66, true) - } - - @JvmStatic - fun isValid(candidate: String, expectedLength: Int, isPrefixRequired: Boolean): Boolean { - val hexCharacters = "0123456789ABCDEF".toSet() - val isValidHexEncoding = hexCharacters.containsAll(candidate.uppercase().toSet()) - val hasValidLength = candidate.length == expectedLength - val hasValidPrefix = if (isPrefixRequired) IdPrefix.fromValue(candidate) != null else true - return isValidHexEncoding && hasValidLength && hasValidPrefix - } + fun isValid(candidate: String, isPrefixRequired: Boolean = true): Boolean = hasValidLength(candidate) && isValidHexEncoding(candidate) && (!isPrefixRequired || IdPrefix.fromValue(candidate) != null) + fun hasValidPrefix(candidate: String) = IdPrefix.fromValue(candidate) !in INVALID_PREFIXES + private fun hasValidLength(candidate: String) = candidate.length == 66 + private fun isValidHexEncoding(candidate: String) = HEX_CHARACTERS.containsAll(candidate.uppercase().toSet()) }