diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/loadaccount/LoadAccountViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/loadaccount/LoadAccountViewModel.kt index 63e089e29b..66cb3e006f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/loadaccount/LoadAccountViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/loadaccount/LoadAccountViewModel.kt @@ -46,7 +46,7 @@ internal class LinkDeviceViewModel @Inject constructor( fun onContinue() { viewModelScope.launch { try { - codec.decodeAsByteArray(state.value.recoveryPhrase).let(::onSuccess) + codec.sanitizeAndDecodeAsByteArray(state.value.recoveryPhrase).let(::onSuccess) } catch (e: Exception) { onFailure(e) } diff --git a/libsession-util/src/test/java/org/session/libsignal/crypto/MnemonicCodecTest.kt b/libsession-util/src/test/java/org/session/libsignal/crypto/MnemonicCodecTest.kt index ec9006a04b..f7b7a5382b 100644 --- a/libsession-util/src/test/java/org/session/libsignal/crypto/MnemonicCodecTest.kt +++ b/libsession-util/src/test/java/org/session/libsignal/crypto/MnemonicCodecTest.kt @@ -76,6 +76,20 @@ class MnemonicCodecTest { assertEquals("0f2ccde528622876b8f16e14db97dafc", result) } + @Test + fun `sanitizeAndDecodeAsByteArray with mnemonic with unnecessary spaces`() { + val result = codec.sanitizeAndDecodeAsByteArray(" fuming nearby kennel husband dejected pepper jaded because dads goggles tufts tomorrow dejected ").let(Hex::toStringCondensed) + + assertEquals("0f2ccde528622876b8f16e14db97dafc", result) + } + + @Test + fun `sanitizeAndDecodeAsByteArray with mnemonic with special characters`() { + val result = codec.sanitizeAndDecodeAsByteArray("...fuming nearby.kennel.husband . dejected pepper jaded because dads goggles tufts tomorrow dejected@").let(Hex::toStringCondensed) + + assertEquals("0f2ccde528622876b8f16e14db97dafc", result) + } + @Test fun `decodeMnemonicOrHexAsByteArray with hex`() { val result = codec.decodeMnemonicOrHexAsByteArray("0f2ccde528622876b8f16e14db97dafc").let(Hex::toStringCondensed) diff --git a/libsignal/src/main/java/org/session/libsignal/crypto/MnemonicCodec.kt b/libsignal/src/main/java/org/session/libsignal/crypto/MnemonicCodec.kt index 7644a023e2..a2ce5e5c53 100644 --- a/libsignal/src/main/java/org/session/libsignal/crypto/MnemonicCodec.kt +++ b/libsignal/src/main/java/org/session/libsignal/crypto/MnemonicCodec.kt @@ -114,8 +114,15 @@ class MnemonicCodec(private val loadFileContents: (String) -> String) { }.joinToString(separator = "") { it } } + fun sanitizeAndDecodeAsByteArray(mnemonic: String): ByteArray = sanitizeRecoveryPhrase(mnemonic).let(::decode).let(Hex::fromStringCondensed) fun decodeAsByteArray(mnemonic: String): ByteArray = decode(mnemonic = mnemonic).let(Hex::fromStringCondensed) + private fun sanitizeRecoveryPhrase(rawMnemonic: String): String = rawMnemonic + .replace("[^\\w]+".toRegex(), " ") // replace any sequence of non-word characters with a space + .trim() // remove leading and trailing whitespace (which may have been from prior special chars) + .split("\\s+".toRegex()) // split on the now properly positioned spaces + .joinToString(" ") // reassemble + fun decodeMnemonicOrHexAsByteArray(mnemonicOrHex: String): ByteArray = try { decode(mnemonic = mnemonicOrHex).let(Hex::fromStringCondensed) } catch (decodeException: Exception) {