Make sure pins up to the max length of 16 digits are supported.
Bug: 284405869 Test: unit tests Change-Id: I9b6ebadde4aa430c78438b6f029b656edf7ebaa0
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.authentication.domain.interactor
|
||||
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import com.android.systemui.authentication.data.repository.AuthenticationRepository
|
||||
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
@@ -177,15 +178,21 @@ constructor(
|
||||
|
||||
/**
|
||||
* Returns a PIN code from the given list. It's assumed the given list elements are all
|
||||
* [Int].
|
||||
* [Int] in the range [0-9].
|
||||
*/
|
||||
private fun List<Any>.asCode(): Int? {
|
||||
if (isEmpty()) {
|
||||
private fun List<Any>.asCode(): Long? {
|
||||
if (isEmpty() || size > DevicePolicyManager.MAX_PASSWORD_LENGTH) {
|
||||
return null
|
||||
}
|
||||
|
||||
var code = 0
|
||||
map { it as Int }.forEach { integer -> code = code * 10 + integer }
|
||||
var code = 0L
|
||||
map {
|
||||
require(it is Int && it in 0..9) {
|
||||
"Pin is required to be Int in range [0..9], but got $it"
|
||||
}
|
||||
it
|
||||
}
|
||||
.forEach { integer -> code = code * 10 + integer }
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
@@ -32,7 +32,13 @@ sealed class AuthenticationMethodModel(
|
||||
/** The most basic authentication method. The lock screen can be swiped away when displayed. */
|
||||
object Swipe : AuthenticationMethodModel(isSecure = false)
|
||||
|
||||
data class Pin(val code: Int) : AuthenticationMethodModel(isSecure = true)
|
||||
/**
|
||||
* Authentication method using a PIN.
|
||||
*
|
||||
* In practice, a pin is restricted to 16 decimal digits , see
|
||||
* [android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH]
|
||||
*/
|
||||
data class Pin(val code: Long) : AuthenticationMethodModel(isSecure = true)
|
||||
|
||||
data class Password(val password: String) : AuthenticationMethodModel(isSecure = true)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.authentication.domain.interactor
|
||||
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.authentication.data.repository.AuthenticationRepository
|
||||
@@ -168,6 +169,51 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withEmptyPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(listOf())).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectMaxLengthPin_returnsTrueAndUnlocksDevice() =
|
||||
testScope.runTest {
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
|
||||
assertThat(isUnlocked).isTrue()
|
||||
assertThat(failedAttemptCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectTooLongPin_returnsFalseAndDoesNotUnlockDevice() =
|
||||
testScope.runTest {
|
||||
// Max pin length is 16 digits. To avoid issues with overflows, this test ensures
|
||||
// that all pins > 16 decimal digits are rejected.
|
||||
|
||||
// If the policy changes, there is work to do in SysUI.
|
||||
assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17)
|
||||
|
||||
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
|
||||
val isUnlocked by collectLastValue(underTest.isUnlocked)
|
||||
underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999))
|
||||
assertThat(isUnlocked).isFalse()
|
||||
|
||||
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
|
||||
assertThat(isUnlocked).isFalse()
|
||||
assertThat(failedAttemptCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticate_withCorrectPassword_returnsTrueAndUnlocksDevice() =
|
||||
testScope.runTest {
|
||||
|
||||
Reference in New Issue
Block a user