Merge pull request #6736 from vector-im/feature/adm/non-ascii-username

Fixes crash when entering non ascii username during account creation
This commit is contained in:
Adam Brown 2022-08-09 11:52:02 +01:00 committed by GitHub
commit 58d47df37b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 19 deletions

1
changelog.d/6735.bugfix Normal file
View File

@ -0,0 +1 @@
Fixes crash when entering non ascii characters during account creation

View File

@ -62,7 +62,10 @@ fun Throwable.isUsernameInUse() = this is Failure.ServerError &&
error.code == MatrixError.M_USER_IN_USE error.code == MatrixError.M_USER_IN_USE
fun Throwable.isInvalidUsername() = this is Failure.ServerError && fun Throwable.isInvalidUsername() = this is Failure.ServerError &&
error.code == MatrixError.M_INVALID_USERNAME (error.code == MatrixError.M_INVALID_USERNAME || usernameContainsNonAsciiCharacters())
private fun Failure.ServerError.usernameContainsNonAsciiCharacters() = error.code == MatrixError.M_UNKNOWN &&
error.message == "Query parameter \'username\' must be ascii"
fun Throwable.isInvalidPassword() = this is Failure.ServerError && fun Throwable.isInvalidPassword() = this is Failure.ServerError &&
error.code == MatrixError.M_FORBIDDEN && error.code == MatrixError.M_FORBIDDEN &&

View File

@ -193,25 +193,32 @@ class OnboardingViewModel @AssistedInject constructor(
} }
private suspend fun checkUserNameAvailability(userName: String) { private suspend fun checkUserNameAvailability(userName: String) {
when (val result = registrationWizard.registrationAvailable(userName)) { runCatching { registrationWizard.registrationAvailable(userName) }.fold(
RegistrationAvailability.Available -> { onSuccess = { result ->
setState { when (result) {
copy( RegistrationAvailability.Available -> {
registrationState = RegistrationState( setState {
isUserNameAvailable = true, copy(
selectedMatrixId = when { registrationState = RegistrationState(
userName.isMatrixId() -> userName isUserNameAvailable = true,
else -> "@$userName:${selectedHomeserver.userFacingUrl.toReducedUrl()}" selectedMatrixId = when {
}, userName.isMatrixId() -> userName
) else -> "@$userName:${selectedHomeserver.userFacingUrl.toReducedUrl()}"
) },
} )
} )
}
}
is RegistrationAvailability.NotAvailable -> { is RegistrationAvailability.NotAvailable -> {
_viewEvents.post(OnboardingViewEvents.Failure(result.failure)) _viewEvents.post(OnboardingViewEvents.Failure(result.failure))
} }
} }
},
onFailure = {
_viewEvents.post(OnboardingViewEvents.Failure(it))
}
)
} }
private fun withAction(action: OnboardingAction, block: (OnboardingAction) -> Unit) { private fun withAction(action: OnboardingAction, block: (OnboardingAction) -> Unit) {

View File

@ -478,6 +478,20 @@ class OnboardingViewModelTest {
.finish() .finish()
} }
@Test
fun `given available username throws, when a register username is entered, then emits error`() = runTest {
viewModelWith(initialRegistrationState(A_HOMESERVER_URL))
fakeAuthenticationService.givenRegistrationWizard(FakeRegistrationWizard().also { it.givenUserNameIsAvailableThrows(A_USERNAME, AN_ERROR) })
val test = viewModel.test()
viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(A_USERNAME))
test
.assertStates(initialState)
.assertEvents(OnboardingViewEvents.Failure(AN_ERROR))
.finish()
}
@Test @Test
fun `given available username, when a register username is entered, then emits available registration state`() = runTest { fun `given available username, when a register username is entered, then emits available registration state`() = runTest {
viewModelWith(initialRegistrationState(A_HOMESERVER_URL)) viewModelWith(initialRegistrationState(A_HOMESERVER_URL))

View File

@ -57,6 +57,10 @@ class FakeRegistrationWizard : RegistrationWizard by mockk(relaxed = false) {
coEvery { registrationAvailable(userName) } returns RegistrationAvailability.Available coEvery { registrationAvailable(userName) } returns RegistrationAvailability.Available
} }
fun givenUserNameIsAvailableThrows(userName: String, cause: Throwable) {
coEvery { registrationAvailable(userName) } throws cause
}
fun givenUserNameIsUnavailable(userName: String, failure: Failure.ServerError) { fun givenUserNameIsUnavailable(userName: String, failure: Failure.ServerError) {
coEvery { registrationAvailable(userName) } returns RegistrationAvailability.NotAvailable(failure) coEvery { registrationAvailable(userName) } returns RegistrationAvailability.NotAvailable(failure)
} }