Skip to content

Commit

Permalink
Merge pull request #3172 from element-hq/feature/bma/pinGracePeriod
Browse files Browse the repository at this point in the history
Set pin grace period to 2 minutes
  • Loading branch information
bmarty authored Jul 10, 2024
2 parents 573cd5e + f73b480 commit 1a03edb
Show file tree
Hide file tree
Showing 35 changed files with 142 additions and 117 deletions.
7 changes: 0 additions & 7 deletions appconfig/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,13 @@
*/
plugins {
id("io.element.android-library")
alias(libs.plugins.anvil)
}

android {
namespace = "io.element.android.appconfig"
}

anvil {
generateDaggerFactories.set(true)
}

dependencies {
implementation(libs.androidx.annotationjvm)
implementation(libs.dagger)
implementation(projects.libraries.di)
implementation(projects.libraries.matrix.api)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,28 @@

package io.element.android.appconfig

import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.AppScope
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/**
* Configuration for the lock screen feature.
* @property isPinMandatory Whether the PIN is mandatory or not.
* @property pinBlacklist Some PINs are forbidden.
* @property pinSize The size of the PIN.
* @property maxPinCodeAttemptsBeforeLogout Number of attempts before the user is logged out.
* @property gracePeriod Time period before locking the app once backgrounded.
* @property isStrongBiometricsEnabled Authentication with strong methods (fingerprint, some face/iris unlock implementations) is supported.
* @property isWeakBiometricsEnabled Authentication with weak methods (most face/iris unlock implementations) is supported.
*/
data class LockScreenConfig(
val isPinMandatory: Boolean,
val pinBlacklist: Set<String>,
val pinSize: Int,
val maxPinCodeAttemptsBeforeLogout: Int,
val gracePeriod: Duration,
val isStrongBiometricsEnabled: Boolean,
val isWeakBiometricsEnabled: Boolean,
)

@ContributesTo(AppScope::class)
@Module
object LockScreenConfigModule {
@Provides
fun providesLockScreenConfig(): LockScreenConfig = LockScreenConfig(
isPinMandatory = false,
pinBlacklist = setOf("0000", "1234"),
pinSize = 4,
maxPinCodeAttemptsBeforeLogout = 3,
gracePeriod = 0.seconds,
isStrongBiometricsEnabled = true,
isWeakBiometricsEnabled = true,
)
import kotlin.time.Duration.Companion.minutes

object LockScreenConfig {
/** Whether the PIN is mandatory or not. */
const val IS_PIN_MANDATORY: Boolean = false

/** Set of forbidden PIN codes. */
val FORBIDDEN_PIN_CODES: Set<String> = setOf("0000", "1234")

/** The size of the PIN. */
const val PIN_SIZE: Int = 4

/** Number of attempts before the user is logged out. */
const val MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT: Int = 3

/** Time period before locking the app once backgrounded. */
val GRACE_PERIOD: Duration = 2.minutes

/** Authentication with strong methods (fingerprint, some face/iris unlock implementations) is supported. */
const val IS_STRONG_BIOMETRICS_ENABLED: Boolean = true

/** Authentication with weak methods (most face/iris unlock implementations) is supported. */
const val IS_WEAK_BIOMETRICS_ENABLED: Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package io.element.android.features.lockscreen.impl

import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.api.LockScreenLockState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager
Expand Down Expand Up @@ -55,7 +54,7 @@ class DefaultLockScreenService @Inject constructor(
private val coroutineScope: CoroutineScope,
private val sessionObserver: SessionObserver,
private val appForegroundStateService: AppForegroundStateService,
private val biometricUnlockManager: BiometricUnlockManager,
biometricUnlockManager: BiometricUnlockManager,
) : LockScreenService {
private val _lockState = MutableStateFlow<LockScreenLockState>(LockScreenLockState.Unlocked)
override val lockState: StateFlow<LockScreenLockState> = _lockState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.element.android.features.lockscreen.impl

import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.AppScope
import kotlin.time.Duration
import io.element.android.appconfig.LockScreenConfig as AppConfigLockScreenConfig

data class LockScreenConfig(
val isPinMandatory: Boolean,
val forbiddenPinCodes: Set<String>,
val pinSize: Int,
val maxPinCodeAttemptsBeforeLogout: Int,
val gracePeriod: Duration,
val isStrongBiometricsEnabled: Boolean,
val isWeakBiometricsEnabled: Boolean,
)

@ContributesTo(AppScope::class)
@Module
object LockScreenConfigModule {
@Provides
fun providesLockScreenConfig(): LockScreenConfig = LockScreenConfig(
isPinMandatory = AppConfigLockScreenConfig.IS_PIN_MANDATORY,
forbiddenPinCodes = AppConfigLockScreenConfig.FORBIDDEN_PIN_CODES,
pinSize = AppConfigLockScreenConfig.PIN_SIZE,
maxPinCodeAttemptsBeforeLogout = AppConfigLockScreenConfig.MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT,
gracePeriod = AppConfigLockScreenConfig.GRACE_PERIOD,
isStrongBiometricsEnabled = AppConfigLockScreenConfig.IS_STRONG_BIOMETRICS_ENABLED,
isWeakBiometricsEnabled = AppConfigLockScreenConfig.IS_WEAK_BIOMETRICS_ENABLED,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import androidx.compose.ui.res.stringResource
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.R
import io.element.android.features.lockscreen.impl.storage.LockScreenStore
import io.element.android.libraries.cryptography.api.EncryptionDecryptionService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager
import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.storage.LockScreenStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
import io.element.android.features.lockscreen.impl.setup.pin.validation.PinValidator
Expand Down Expand Up @@ -76,7 +76,7 @@ class SetupPinPresenter @Inject constructor(
if (confirmPinEntry == choosePinEntry) {
pinCodeManager.createPinCode(confirmPinEntry.toText())
} else {
setupPinFailure = SetupPinFailure.PinsDontMatch
setupPinFailure = SetupPinFailure.PinsDoNotMatch
}
}
}
Expand All @@ -93,11 +93,11 @@ class SetupPinPresenter @Inject constructor(
}
SetupPinEvents.ClearFailure -> {
when (setupPinFailure) {
is SetupPinFailure.PinsDontMatch -> {
is SetupPinFailure.PinsDoNotMatch -> {
choosePinEntry = choosePinEntry.clear()
confirmPinEntry = confirmPinEntry.clear()
}
is SetupPinFailure.PinBlacklisted -> {
is SetupPinFailure.ForbiddenPin -> {
choosePinEntry = choosePinEntry.clear()
}
null -> Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ open class SetupPinStateProvider : PreviewParameterProvider<SetupPinState> {
choosePinEntry = PinEntry.createEmpty(4).fillWith("1789"),
confirmPinEntry = PinEntry.createEmpty(4).fillWith("1788"),
isConfirmationStep = true,
creationFailure = SetupPinFailure.PinsDontMatch
creationFailure = SetupPinFailure.PinsDoNotMatch
),
aSetupPinState(
choosePinEntry = PinEntry.createEmpty(4).fillWith("1111"),
creationFailure = SetupPinFailure.PinBlacklisted
creationFailure = SetupPinFailure.ForbiddenPin
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,16 @@ private fun SetupPinContent(
@Composable
private fun SetupPinFailure.content(): String {
return when (this) {
SetupPinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_content)
SetupPinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_content)
SetupPinFailure.ForbiddenPin -> stringResource(id = R.string.screen_app_lock_setup_pin_forbidden_dialog_content)
SetupPinFailure.PinsDoNotMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_content)
}
}

@Composable
private fun SetupPinFailure.title(): String {
return when (this) {
SetupPinFailure.PinBlacklisted -> stringResource(id = R.string.screen_app_lock_setup_pin_blacklisted_dialog_title)
SetupPinFailure.PinsDontMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_title)
SetupPinFailure.ForbiddenPin -> stringResource(id = R.string.screen_app_lock_setup_pin_forbidden_dialog_title)
SetupPinFailure.PinsDoNotMatch -> stringResource(id = R.string.screen_app_lock_setup_pin_mismatch_dialog_title)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package io.element.android.features.lockscreen.impl.setup.pin.validation

import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
import javax.inject.Inject

Expand All @@ -28,9 +28,9 @@ class PinValidator @Inject constructor(private val lockScreenConfig: LockScreenC

fun isPinValid(pinEntry: PinEntry): Result {
val pinAsText = pinEntry.toText()
val isBlacklisted = lockScreenConfig.pinBlacklist.any { it == pinAsText }
return if (isBlacklisted) {
Result.Invalid(SetupPinFailure.PinBlacklisted)
val isForbidden = lockScreenConfig.forbiddenPinCodes.any { it == pinAsText }
return if (isForbidden) {
Result.Invalid(SetupPinFailure.ForbiddenPin)
} else {
Result.Valid
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
package io.element.android.features.lockscreen.impl.setup.pin.validation

sealed interface SetupPinFailure {
data object PinBlacklisted : SetupPinFailure
data object PinsDontMatch : SetupPinFailure
data object ForbiddenPin : SetupPinFailure
data object PinsDoNotMatch : SetupPinFailure
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SingleIn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Эканомце час і выкарыстоўвайце %1$s для разблакіроўкі праграмы"</string>
<string name="screen_app_lock_setup_choose_pin">"Выберыце PIN-код"</string>
<string name="screen_app_lock_setup_confirm_pin">"Пацвярджэнне PIN-кода"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Вы не можаце выбраць гэты PIN-код з меркаванняў бяспекі"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Выберыце іншы PIN-код"</string>
<string name="screen_app_lock_setup_pin_context">"Заблакіруйце %1$s, каб павялічыць бяспеку вашых чатаў.

Абярыце што-небудзь незабыўнае. Калі вы забудзецеся гэты PIN-код, вы выйдзеце з праграмы."</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_content">"Вы не можаце выбраць гэты PIN-код з меркаванняў бяспекі"</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_title">"Выберыце іншы PIN-код"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Увядзіце адзін і той жа PIN двойчы"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"PIN-коды не супадаюць"</string>
<string name="screen_app_lock_signout_alert_message">"Каб працягнуць, вам неабходна паўторна ўвайсці ў сістэму і стварыць новы PIN-код"</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<string name="screen_app_lock_setup_biometric_unlock_skip">"Предпочитам да използвам PIN"</string>
<string name="screen_app_lock_setup_choose_pin">"Избор на PIN"</string>
<string name="screen_app_lock_setup_confirm_pin">"Потвърждаване на PIN"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Избор на различен PIN"</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_title">"Избор на различен PIN"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Моля, въведете един и същ PIN два пъти"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"PINs не съвпадат"</string>
<plurals name="screen_app_lock_subtitle">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Ušetřete si čas a použijte pokaždé %1$s pro odemknutí aplikace"</string>
<string name="screen_app_lock_setup_choose_pin">"Zvolte PIN"</string>
<string name="screen_app_lock_setup_confirm_pin">"Potvrďte PIN"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Z bezpečnostních důvodů si toto nemůžete zvolit jako svůj PIN kód"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Zvolte jiný PIN"</string>
<string name="screen_app_lock_setup_pin_context">"Zamkněte %1$s pro zvýšení bezpečnosti vašich konverzací.

Vyberte si něco zapamatovatelného. Pokud tento kód PIN zapomenete, budete z aplikace odhlášeni."</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_content">"Z bezpečnostních důvodů si toto nemůžete zvolit jako svůj PIN kód"</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_title">"Zvolte jiný PIN"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Zadejte stejný PIN dvakrát"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"PIN kódy se neshodují."</string>
<string name="screen_app_lock_signout_alert_message">"Abyste mohli pokračovat, budete se muset znovu přihlásit a vytvořit nový PIN"</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Spare dir etwas Zeit und benutze %1$s, um die App zu entsperren"</string>
<string name="screen_app_lock_setup_choose_pin">"PIN wählen"</string>
<string name="screen_app_lock_setup_confirm_pin">"PIN bestätigen"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Aus Sicherheitsgründen kann dieser PIN-Code nicht verwendet werden."</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Bitte eine andere PIN verwenden."</string>
<string name="screen_app_lock_setup_pin_context">"Sperre %1$s mit einem PIN Code, um den Zugriff auf deine Chats zu beschränken.

Wähle etwas Einprägsames. Bei falscher Eingabe wirst du aus der App ausgeloggt."</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_content">"Aus Sicherheitsgründen kann dieser PIN-Code nicht verwendet werden."</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_title">"Bitte eine andere PIN verwenden."</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Bitte gib die gleiche PIN wie zuvor ein."</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"Die PINs stimmen nicht überein"</string>
<string name="screen_app_lock_signout_alert_message">"Um fortzufahren, musst du dich erneut anmelden und eine neue PIN erstellen"</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Εξοικονόμησε χρόνο και χρησιμοποίησε %1$s για να ξεκλειδώσεις την εφαρμογή κάθε φορά"</string>
<string name="screen_app_lock_setup_choose_pin">"Επέλεξε PIN"</string>
<string name="screen_app_lock_setup_confirm_pin">"Επιβεβαίωση PIN"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Δεν μπορείς να το επιλέξεις ως κωδικό PIN για λόγους ασφαλείας"</string>
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Επέλεξε διαφορετικό PIN"</string>
<string name="screen_app_lock_setup_pin_context">"Κλείδωμα του %1$s για να προσθέσεις επιπλέον ασφάλεια στις συνομιλίες σου.

Επέλεξε κάτι αξιομνημόνευτο. Εάν ξεχάσεις αυτό το PIN, θα αποσυνδεθείς από την εφαρμογή."</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_content">"Δεν μπορείς να το επιλέξεις ως κωδικό PIN για λόγους ασφαλείας"</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_title">"Επέλεξε διαφορετικό PIN"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Παρακαλώ εισήγαγε το ίδιο PIN δύο φορές"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"Τα PIN δεν ταιριάζουν"</string>
<string name="screen_app_lock_signout_alert_message">"Θα χρειαστεί να συνδεθείς ξανά και να δημιουργήσεις ένα νέο PIN για να προχωρήσεις"</string>
Expand Down
Loading

0 comments on commit 1a03edb

Please sign in to comment.