Skip to content

Commit 39c15b8

Browse files
authored
Merge pull request #119 from synonymdev/feat/pin-attempts-zero-wipe
feat: Wipe wallet on too many PIN attempts
2 parents 52aabbf + 6e43b8c commit 39c15b8

File tree

6 files changed

+30
-9
lines changed

6 files changed

+30
-9
lines changed

app/src/main/java/to/bitkit/services/LdkNodeEventBus.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import javax.inject.Singleton
88

99
@Singleton
1010
class LdkNodeEventBus @Inject constructor() {
11-
private val _events = MutableSharedFlow<Event>(replay = 0, extraBufferCapacity = 1)
11+
private val _events = MutableSharedFlow<Event>(extraBufferCapacity = 1)
1212
val events = _events.asSharedFlow()
1313

1414
suspend fun emit(event: Event) {

app/src/main/java/to/bitkit/ui/ContentView.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ fun ContentView(
159159
appViewModel.mainScreenEffect.collect {
160160
when (it) {
161161
is MainScreenEffect.NavigateActivityDetail -> navController.navigate(Routes.ActivityItem(it.activityId))
162+
else -> Unit
162163
}
163164
}
164165
}

app/src/main/java/to/bitkit/ui/MainActivity.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.activity.viewModels
66
import androidx.compose.animation.AnimatedVisibility
77
import androidx.compose.animation.fadeIn
88
import androidx.compose.animation.fadeOut
9+
import androidx.compose.runtime.LaunchedEffect
910
import androidx.compose.runtime.getValue
1011
import androidx.compose.runtime.rememberCoroutineScope
1112
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
@@ -40,6 +41,7 @@ import to.bitkit.viewmodels.ActivityListViewModel
4041
import to.bitkit.viewmodels.AppViewModel
4142
import to.bitkit.viewmodels.BlocktankViewModel
4243
import to.bitkit.viewmodels.CurrencyViewModel
44+
import to.bitkit.viewmodels.MainScreenEffect
4345
import to.bitkit.viewmodels.TransferViewModel
4446
import to.bitkit.viewmodels.WalletViewModel
4547

@@ -210,6 +212,15 @@ class MainActivity : FragmentActivity() {
210212
onResetClick = { walletViewModel.wipeStorage() },
211213
)
212214
}
215+
216+
LaunchedEffect(appViewModel) {
217+
appViewModel.mainScreenEffect.collect {
218+
when (it) {
219+
MainScreenEffect.WipeStorage -> walletViewModel.wipeStorage()
220+
else -> Unit
221+
}
222+
}
223+
}
213224
}
214225

215226
ToastOverlay(

app/src/main/java/to/bitkit/ui/shared/toast/ToastEventBus.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.asSharedFlow
55
import to.bitkit.models.Toast
66

77
object ToastEventBus {
8-
private val _events = MutableSharedFlow<Toast>(replay = 0, extraBufferCapacity = 1)
8+
private val _events = MutableSharedFlow<Toast>(extraBufferCapacity = 1)
99
val events = _events.asSharedFlow()
1010

1111
suspend fun send(

app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.compose.runtime.setValue
66
import androidx.lifecycle.ViewModel
77
import androidx.lifecycle.viewModelScope
88
import dagger.hilt.android.lifecycle.HiltViewModel
9+
import kotlinx.coroutines.CoroutineDispatcher
910
import kotlinx.coroutines.Dispatchers
1011
import kotlinx.coroutines.delay
1112
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -22,8 +23,10 @@ import kotlinx.coroutines.launch
2223
import org.lightningdevkit.ldknode.Event
2324
import org.lightningdevkit.ldknode.PaymentId
2425
import org.lightningdevkit.ldknode.Txid
26+
import to.bitkit.R
2527
import to.bitkit.data.SettingsStore
2628
import to.bitkit.data.keychain.Keychain
29+
import to.bitkit.di.BgDispatcher
2730
import to.bitkit.env.Env
2831
import to.bitkit.ext.WatchResult
2932
import to.bitkit.ext.removeSpaces
@@ -44,6 +47,7 @@ import to.bitkit.ui.components.BottomSheetType
4447
import to.bitkit.ui.screens.wallets.send.SendRoute
4548
import to.bitkit.ui.shared.toast.ToastEventBus
4649
import to.bitkit.utils.Logger
50+
import to.bitkit.utils.ResourceProvider
4751
import uniffi.bitkitcore.Activity
4852
import uniffi.bitkitcore.ActivityFilter
4953
import uniffi.bitkitcore.LightningInvoice
@@ -54,12 +58,14 @@ import javax.inject.Inject
5458

5559
@HiltViewModel
5660
class AppViewModel @Inject constructor(
61+
@BgDispatcher private val bgDispatcher: CoroutineDispatcher,
5762
private val keychain: Keychain,
5863
private val scannerService: ScannerService,
5964
private val lightningService: LightningRepo,
6065
private val coreService: CoreService,
6166
private val ldkNodeEventBus: LdkNodeEventBus,
6267
private val settingsStore: SettingsStore,
68+
private val resourceProvider: ResourceProvider,
6369
) : ViewModel() {
6470
var splashVisible by mutableStateOf(true)
6571
private set
@@ -70,11 +76,11 @@ class AppViewModel @Inject constructor(
7076
private val _sendUiState = MutableStateFlow(SendUiState())
7177
val sendUiState = _sendUiState.asStateFlow()
7278

73-
private val _sendEffect = MutableSharedFlow<SendEffect>(replay = 0, extraBufferCapacity = 1)
79+
private val _sendEffect = MutableSharedFlow<SendEffect>(extraBufferCapacity = 1)
7480
val sendEffect = _sendEffect.asSharedFlow()
7581
private fun setSendEffect(effect: SendEffect) = viewModelScope.launch { _sendEffect.emit(effect) }
7682

77-
private val _mainScreenEffect = MutableSharedFlow<MainScreenEffect>(replay = 0, extraBufferCapacity = 1)
83+
private val _mainScreenEffect = MutableSharedFlow<MainScreenEffect>(extraBufferCapacity = 1)
7884
val mainScreenEffect = _mainScreenEffect.asSharedFlow()
7985
private fun mainScreenEffect(effect: MainScreenEffect) = viewModelScope.launch { _mainScreenEffect.emit(effect) }
8086

@@ -820,16 +826,18 @@ class AppViewModel @Inject constructor(
820826
return true
821827
}
822828

823-
viewModelScope.launch {
829+
viewModelScope.launch(bgDispatcher) {
824830
val newAttempts = pinAttemptsRemaining.value - 1
825831
keychain.upsertString(Keychain.Key.PIN_ATTEMPTS_REMAINING.name, newAttempts.toString())
826832

827833
if (newAttempts <= 0) {
828-
// TODO: wipeStorage() & return to onboarding
829834
toast(
830-
type = Toast.ToastType.WARNING,
831-
title = "TODO: Wipe App data",
835+
type = Toast.ToastType.SUCCESS,
836+
title = resourceProvider.getString(R.string.security__wiped_title),
837+
description = resourceProvider.getString(R.string.security__wiped_message),
832838
)
839+
delay(250) // small delay for UI feedback
840+
mainScreenEffect(MainScreenEffect.WipeStorage)
833841
}
834842
}
835843
return false
@@ -892,6 +900,7 @@ sealed class SendEffect {
892900

893901
sealed class MainScreenEffect {
894902
data class NavigateActivityDetail(val activityId: String) : MainScreenEffect()
903+
data object WipeStorage : MainScreenEffect()
895904
}
896905

897906
sealed class SendEvent {

app/src/main/java/to/bitkit/viewmodels/ExternalNodeViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class ExternalNodeViewModel @Inject constructor(
3333
private val _uiState = MutableStateFlow(UiState())
3434
val uiState = _uiState.asStateFlow()
3535

36-
private val _effects = MutableSharedFlow<SideEffect>(replay = 0, extraBufferCapacity = 1)
36+
private val _effects = MutableSharedFlow<SideEffect>(extraBufferCapacity = 1)
3737
val effects = _effects.asSharedFlow()
3838
private fun setEffect(effect: SideEffect) = viewModelScope.launch { _effects.emit(effect) }
3939

0 commit comments

Comments
 (0)