Skip to content

Commit f19cb1b

Browse files
committed
feat: add debug CRL refresh controls
1 parent 089b4a5 commit f19cb1b

9 files changed

Lines changed: 152 additions & 3 deletions

File tree

app/src/main/kotlin/com/wire/android/di/accountScoped/DebugModule.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import com.wire.kalium.logic.feature.debug.GetDebugE2EICertificateExpirationUseC
2727
import com.wire.kalium.logic.feature.debug.GetFeatureConfigUseCase
2828
import com.wire.kalium.logic.feature.debug.GetConversationCryptoStatsUseCase
2929
import com.wire.kalium.logic.feature.debug.GetConversationEpochFromCCUseCase
30+
import com.wire.kalium.logic.feature.debug.ObserveDebugCRLExpirationAfterOneMinuteUseCase
3031
import com.wire.kalium.logic.feature.debug.RepairFaultyRemovalKeysUseCase
32+
import com.wire.kalium.logic.feature.debug.SetDebugCRLExpirationAfterOneMinuteUseCase
3133
import com.wire.kalium.logic.feature.debug.SetDebugE2EICertificateExpirationUseCase
3234
import dagger.Module
3335
import dagger.Provides
@@ -94,6 +96,20 @@ class DebugModule {
9496
fun provideSetDebugE2EICertificateExpirationUseCase(debugScope: DebugScope): SetDebugE2EICertificateExpirationUseCase =
9597
debugScope.setDebugE2EICertificateExpiration
9698

99+
@ViewModelScoped
100+
@Provides
101+
fun provideObserveDebugCRLExpirationAfterOneMinuteUseCase(
102+
debugScope: DebugScope
103+
): ObserveDebugCRLExpirationAfterOneMinuteUseCase =
104+
debugScope.observeDebugCRLExpirationAfterOneMinute
105+
106+
@ViewModelScoped
107+
@Provides
108+
fun provideSetDebugCRLExpirationAfterOneMinuteUseCase(
109+
debugScope: DebugScope
110+
): SetDebugCRLExpirationAfterOneMinuteUseCase =
111+
debugScope.setDebugCRLExpirationAfterOneMinute
112+
97113
@ViewModelScoped
98114
@Provides
99115
fun provideGetConversationEpochFromCCUseCase(debugScope: DebugScope): GetConversationEpochFromCCUseCase =

app/src/main/kotlin/com/wire/android/ui/debug/DebugDataOptions.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ fun DebugDataOptions(
8686
handleE2EIEnrollmentResult = viewModel::handleE2EIEnrollmentResult,
8787
dismissCertificateDialog = viewModel::dismissCertificateDialog,
8888
checkCrlRevocationList = viewModel::checkCrlRevocationList,
89+
forceCRLExpirationAfterOneMinute = viewModel.state.forceCRLExpirationAfterOneMinute,
90+
onForceCRLExpirationAfterOneMinuteChange = viewModel::forceCRLExpirationAfterOneMinute,
8991
onResendFCMToken = viewModel::forceSendFCMToken,
9092
onEnableAsyncNotificationsChange = viewModel::enableAsyncNotifications,
9193
onShowFeatureFlags = onShowFeatureFlags,
@@ -110,6 +112,8 @@ fun DebugDataOptionsContent(
110112
handleE2EIEnrollmentResult: (FinalizeEnrollmentResult) -> Unit,
111113
dismissCertificateDialog: () -> Unit,
112114
checkCrlRevocationList: () -> Unit,
115+
forceCRLExpirationAfterOneMinute: Boolean,
116+
onForceCRLExpirationAfterOneMinuteChange: (Boolean) -> Unit,
113117
onResendFCMToken: () -> Unit,
114118
onShowFeatureFlags: () -> Unit,
115119
onShowCryptoStats: () -> Unit,
@@ -248,6 +252,8 @@ fun DebugDataOptionsContent(
248252
onRestartSlowSyncForRecovery = onRestartSlowSyncForRecovery,
249253
onForceUpdateApiVersions = onForceUpdateApiVersions,
250254
checkCrlRevocationList = checkCrlRevocationList,
255+
forceCRLExpirationAfterOneMinute = forceCRLExpirationAfterOneMinute,
256+
onForceCRLExpirationAfterOneMinuteChange = onForceCRLExpirationAfterOneMinuteChange,
251257
onResendFCMToken = onResendFCMToken,
252258
isAsyncNotificationsEnabled = state.isAsyncNotificationsEnabled,
253259
onEnableAsyncNotificationsChange = onEnableAsyncNotificationsChange
@@ -408,6 +414,8 @@ fun PreviewOtherDebugOptions() = WireTheme {
408414
handleE2EIEnrollmentResult = {},
409415
dismissCertificateDialog = {},
410416
checkCrlRevocationList = {},
417+
forceCRLExpirationAfterOneMinute = false,
418+
onForceCRLExpirationAfterOneMinuteChange = {},
411419
onResendFCMToken = {},
412420
onEnableAsyncNotificationsChange = {},
413421
onShowFeatureFlags = {},

app/src/main/kotlin/com/wire/android/ui/debug/DebugDataOptionsState.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ data class DebugDataOptionsState(
2626
val showCertificate: Boolean = false,
2727
val startGettingE2EICertificate: Boolean = false,
2828
val e2eiCertificateExpirationSeconds: Long = 360L,
29+
val forceCRLExpirationAfterOneMinute: Boolean = false,
2930
val analyticsTrackingId: String = "null",
3031
val isFederationEnabled: Boolean = false,
3132
val currentApiVersion: String = "null",

app/src/main/kotlin/com/wire/android/ui/debug/DebugDataOptionsViewModel.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ import com.wire.kalium.logic.feature.debug.StartUsingAsyncNotificationsResult
4545
import com.wire.kalium.logic.feature.debug.StartUsingAsyncNotificationsUseCase
4646
import com.wire.kalium.logic.feature.debug.GetDebugE2EICertificateExpirationUseCase
4747
import com.wire.kalium.logic.feature.debug.MIN_DEBUG_E2EI_CERTIFICATE_EXPIRATION_SECONDS
48+
import com.wire.kalium.logic.feature.debug.ObserveDebugCRLExpirationAfterOneMinuteUseCase
49+
import com.wire.kalium.logic.feature.debug.SetDebugCRLExpirationAfterOneMinuteUseCase
4850
import com.wire.kalium.logic.feature.debug.SetDebugE2EICertificateExpirationUseCase
4951
import com.wire.kalium.logic.feature.debug.TargetedRepairParam
5052
import com.wire.kalium.logic.feature.e2ei.CheckCrlRevocationListUseCase
@@ -79,6 +81,7 @@ interface DebugDataOptionsViewModel {
7981
val e2eiCertificateExpirationInputState: TextFieldState get() = TextFieldState("6")
8082
fun currentAccount(): UserId = UserId("value", "domain")
8183
fun checkCrlRevocationList() {}
84+
fun forceCRLExpirationAfterOneMinute(enabled: Boolean) {}
8285
fun restartSlowSyncForRecovery() {}
8386
fun enrollE2EICertificate() {}
8487
fun updateE2EICertificateExpiration(seconds: Long) {}
@@ -113,6 +116,8 @@ class DebugDataOptionsViewModelImpl
113116
private val repairFaultyRemovalKeys: RepairFaultyRemovalKeysUseCase,
114117
private val getDebugE2EICertificateExpiration: GetDebugE2EICertificateExpirationUseCase,
115118
private val setDebugE2EICertificateExpiration: SetDebugE2EICertificateExpirationUseCase,
119+
private val observeDebugCRLExpirationAfterOneMinute: ObserveDebugCRLExpirationAfterOneMinuteUseCase,
120+
private val setDebugCRLExpirationAfterOneMinute: SetDebugCRLExpirationAfterOneMinuteUseCase,
116121
) : ViewModel(), DebugDataOptionsViewModel {
117122
private companion object {
118123
val DEFAULT_DEBUG_E2EI_CERTIFICATE_EXPIRATION_SECONDS = 90.days.inWholeSeconds
@@ -133,6 +138,7 @@ class DebugDataOptionsViewModelImpl
133138
init {
134139
observeAsyncNotificationsEnabledData()
135140
observeMlsMetadata()
141+
observeDebugCRLExpiration()
136142
observeE2EICertificateExpirationInput()
137143
setGitHashAndDeviceId()
138144
setAnalyticsTrackingId()
@@ -205,6 +211,15 @@ class DebugDataOptionsViewModelImpl
205211
}
206212
}
207213

214+
override fun forceCRLExpirationAfterOneMinute(enabled: Boolean) {
215+
viewModelScope.launch {
216+
setDebugCRLExpirationAfterOneMinute(enabled)
217+
if (enabled) {
218+
checkCrlRevocationList(forceUpdate = true)
219+
}
220+
}
221+
}
222+
208223
override fun restartSlowSyncForRecovery() {
209224
viewModelScope.launch {
210225
restartSlowSyncProcessForRecovery()
@@ -373,6 +388,14 @@ class DebugDataOptionsViewModelImpl
373388
}
374389
}
375390

391+
private fun observeDebugCRLExpiration() {
392+
viewModelScope.launch {
393+
observeDebugCRLExpirationAfterOneMinute().collect { enabled ->
394+
state = state.copy(forceCRLExpirationAfterOneMinute = enabled)
395+
}
396+
}
397+
}
398+
376399
private fun loadDebugE2EICertificateExpiration() {
377400
viewModelScope.launch {
378401
val currentExpiration = getDebugE2EICertificateExpiration()

app/src/main/kotlin/com/wire/android/ui/debug/DebugToolsOptions.kt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ private fun DebugToolsOptionsPreview() {
4949
onRestartSlowSyncForRecovery = {},
5050
onForceUpdateApiVersions = {},
5151
checkCrlRevocationList = {},
52+
forceCRLExpirationAfterOneMinute = false,
53+
onForceCRLExpirationAfterOneMinuteChange = {},
5254
onResendFCMToken = {},
5355
isAsyncNotificationsEnabled = true,
5456
onEnableAsyncNotificationsChange = {}
@@ -63,6 +65,8 @@ internal fun DebugToolsOptions(
6365
onRestartSlowSyncForRecovery: () -> Unit,
6466
onForceUpdateApiVersions: () -> Unit,
6567
checkCrlRevocationList: () -> Unit,
68+
forceCRLExpirationAfterOneMinute: Boolean,
69+
onForceCRLExpirationAfterOneMinuteChange: (Boolean) -> Unit,
6670
onResendFCMToken: () -> Unit,
6771
isAsyncNotificationsEnabled: Boolean,
6872
onEnableAsyncNotificationsChange: (Boolean) -> Unit,
@@ -76,6 +80,8 @@ internal fun DebugToolsOptions(
7680
onRestartSlowSyncForRecovery = onRestartSlowSyncForRecovery,
7781
onForceUpdateApiVersions = onForceUpdateApiVersions,
7882
checkCrlRevocationList = checkCrlRevocationList,
83+
forceCRLExpirationAfterOneMinute = forceCRLExpirationAfterOneMinute,
84+
onForceCRLExpirationAfterOneMinuteChange = onForceCRLExpirationAfterOneMinuteChange,
7985
isAsyncNotificationsEnabled = isAsyncNotificationsEnabled,
8086
onEnableAsyncNotificationsChange = onEnableAsyncNotificationsChange
8187
)
@@ -91,6 +97,8 @@ private fun PrivateBuildDebugToolsOptions(
9197
onRestartSlowSyncForRecovery: () -> Unit,
9298
onForceUpdateApiVersions: () -> Unit,
9399
checkCrlRevocationList: () -> Unit,
100+
forceCRLExpirationAfterOneMinute: Boolean,
101+
onForceCRLExpirationAfterOneMinuteChange: (Boolean) -> Unit,
94102
isAsyncNotificationsEnabled: Boolean,
95103
onEnableAsyncNotificationsChange: (Boolean) -> Unit,
96104
) {
@@ -100,6 +108,10 @@ private fun PrivateBuildDebugToolsOptions(
100108
onCheckedChange = onDisableEventProcessingChange
101109
)
102110
RestartSlowSyncButton(onClick = onRestartSlowSyncForRecovery)
111+
ForceCRLExpirationAfterOneMinuteSwitch(
112+
isEnabled = forceCRLExpirationAfterOneMinute,
113+
onCheckedChange = onForceCRLExpirationAfterOneMinuteChange
114+
)
103115
CheckCrlRevocationButton(onClick = checkCrlRevocationList)
104116
ForceUpdateApiVersionsButton(onClick = onForceUpdateApiVersions)
105117
EnableAsyncNotifications(isAsyncNotificationsEnabled, onEnableAsyncNotificationsChange)
@@ -142,6 +154,35 @@ private fun DisableEventProcessingSwitch(
142154
)
143155
}
144156

157+
@Composable
158+
private fun ForceCRLExpirationAfterOneMinuteSwitch(
159+
isEnabled: Boolean = false,
160+
onCheckedChange: ((Boolean) -> Unit)?,
161+
) {
162+
RowItemTemplate(
163+
title = {
164+
Text(
165+
style = MaterialTheme.wireTypography.body01,
166+
color = MaterialTheme.wireColorScheme.onBackground,
167+
text = "Force CRL expiry after 1 minute",
168+
modifier = Modifier.padding(start = dimensions().spacing8x)
169+
)
170+
},
171+
actions = {
172+
WireSwitch(
173+
checked = isEnabled,
174+
onCheckedChange = onCheckedChange,
175+
modifier = Modifier
176+
.padding(end = dimensions().spacing8x)
177+
.size(
178+
width = dimensions().buttonSmallMinSize.width,
179+
height = dimensions().buttonSmallMinSize.height
180+
)
181+
)
182+
}
183+
)
184+
}
185+
145186
@Composable
146187
private fun RestartSlowSyncButton(
147188
onClick: () -> Unit,

app/src/main/kotlin/com/wire/android/ui/home/AppSyncViewModel.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ import androidx.lifecycle.ViewModel
2121
import androidx.lifecycle.viewModelScope
2222
import com.wire.android.appLogger
2323
import com.wire.android.util.dispatchers.DispatcherProvider
24+
import com.wire.kalium.logic.feature.debug.ObserveDebugCRLExpirationAfterOneMinuteUseCase
2425
import com.wire.kalium.logic.sync.ForegroundActionsUseCase
2526
import dagger.hilt.android.lifecycle.HiltViewModel
2627
import kotlinx.coroutines.Job
28+
import kotlinx.coroutines.flow.launchIn
29+
import kotlinx.coroutines.flow.onEach
2730
import kotlinx.coroutines.launch
2831
import kotlinx.datetime.Clock
2932
import kotlinx.datetime.Instant
@@ -34,14 +37,27 @@ import kotlin.time.Duration.Companion.minutes
3437
@HiltViewModel
3538
class AppSyncViewModel @Inject constructor(
3639
private val foregroundActionsUseCase: ForegroundActionsUseCase,
40+
observeDebugCRLExpirationAfterOneMinute: ObserveDebugCRLExpirationAfterOneMinuteUseCase,
3741
private val dispatcher: DispatcherProvider,
3842
) : ViewModel() {
3943

40-
private val minIntervalBetweenPulls: Duration = MIN_INTERVAL_BETWEEN_PULLS
44+
private var minIntervalBetweenPulls: Duration = MIN_INTERVAL_BETWEEN_PULLS
4145

4246
private var lastPullInstant: Instant? = null
4347
private var syncDataJob: Job? = null
4448

49+
init {
50+
observeDebugCRLExpirationAfterOneMinute()
51+
.onEach { isForced ->
52+
minIntervalBetweenPulls = if (isForced) {
53+
MIN_INTERVAL_BETWEEN_FORCED_CRL_PULLS
54+
} else {
55+
MIN_INTERVAL_BETWEEN_PULLS
56+
}
57+
}
58+
.launchIn(viewModelScope)
59+
}
60+
4561
fun startSyncingAppConfig() {
4662
if (isSyncing()) return
4763

@@ -75,5 +91,6 @@ class AppSyncViewModel @Inject constructor(
7591

7692
companion object {
7793
val MIN_INTERVAL_BETWEEN_PULLS = 60.minutes
94+
val MIN_INTERVAL_BETWEEN_FORCED_CRL_PULLS = 1.minutes
7895
}
7996
}

app/src/test/kotlin/com/wire/android/ui/home/AppSyncViewModelTest.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ package com.wire.android.ui.home
1919

2020
import com.wire.android.config.CoroutineTestExtension
2121
import com.wire.android.config.TestDispatcherProvider
22+
import com.wire.kalium.logic.feature.debug.ObserveDebugCRLExpirationAfterOneMinuteUseCase
2223
import com.wire.kalium.logic.sync.ForegroundActionsUseCase
2324
import io.mockk.MockKAnnotations
2425
import io.mockk.coEvery
2526
import io.mockk.coVerify
27+
import io.mockk.every
2628
import io.mockk.impl.annotations.MockK
2729
import kotlinx.coroutines.delay
30+
import kotlinx.coroutines.flow.flowOf
2831
import kotlinx.coroutines.test.advanceUntilIdle
2932
import kotlinx.coroutines.test.runTest
3033
import org.junit.jupiter.api.Test
@@ -65,8 +68,12 @@ class AppSyncViewModelTest {
6568
@MockK
6669
lateinit var foregroundActionsUseCase: ForegroundActionsUseCase
6770

71+
@MockK
72+
lateinit var observeDebugCRLExpirationAfterOneMinute: ObserveDebugCRLExpirationAfterOneMinuteUseCase
73+
6874
init {
6975
MockKAnnotations.init(this)
76+
every { observeDebugCRLExpirationAfterOneMinute() } returns flowOf(false)
7077
}
7178

7279
fun withForegroundActionsUseCase(delayMs: Long = 0) {
@@ -78,6 +85,7 @@ class AppSyncViewModelTest {
7885
fun arrange(testDispatcher: TestDispatcherProvider, block: Arrangement.() -> Unit) = apply(block).let {
7986
this to AppSyncViewModel(
8087
foregroundActionsUseCase = foregroundActionsUseCase,
88+
observeDebugCRLExpirationAfterOneMinute = observeDebugCRLExpirationAfterOneMinute,
8189
dispatcher = testDispatcher
8290
)
8391
}

app/src/test/kotlin/com/wire/android/ui/settings/debug/DebugDataOptionsViewModelTest.kt

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import com.wire.kalium.logic.feature.debug.StartUsingAsyncNotificationsResult
4242
import com.wire.kalium.logic.feature.debug.StartUsingAsyncNotificationsUseCase
4343
import com.wire.kalium.logic.feature.debug.GetDebugE2EICertificateExpirationUseCase
4444
import com.wire.kalium.logic.feature.debug.MIN_DEBUG_E2EI_CERTIFICATE_EXPIRATION_SECONDS
45+
import com.wire.kalium.logic.feature.debug.ObserveDebugCRLExpirationAfterOneMinuteUseCase
46+
import com.wire.kalium.logic.feature.debug.SetDebugCRLExpirationAfterOneMinuteUseCase
4547
import com.wire.kalium.logic.feature.debug.SetDebugE2EICertificateExpirationUseCase
4648
import com.wire.kalium.logic.feature.e2ei.CheckCrlRevocationListUseCase
4749
import com.wire.kalium.logic.feature.keypackage.MLSKeyPackageCountResult
@@ -287,6 +289,25 @@ class DebugDataOptionsViewModelTest {
287289
coVerify(exactly = 1) { arrangement.setDebugE2EICertificateExpiration(420) }
288290
assertEquals(420, viewModel.state.e2eiCertificateExpirationSeconds)
289291
}
292+
293+
@Test
294+
fun `given CRL force expiration is observed, then view state contains loaded value`() = runTest {
295+
val (_, viewModel) = DebugDataOptionsHiltArrangement()
296+
.withDebugCRLExpirationAfterOneMinute(true)
297+
.arrange()
298+
299+
assertEquals(true, viewModel.state.forceCRLExpirationAfterOneMinute)
300+
}
301+
302+
@Test
303+
fun `when forcing CRL expiration after one minute, then setting use case is called`() = runTest {
304+
val (arrangement, viewModel) = DebugDataOptionsHiltArrangement().arrange()
305+
306+
viewModel.forceCRLExpirationAfterOneMinute(true)
307+
308+
coVerify(exactly = 1) { arrangement.setDebugCRLExpirationAfterOneMinute(true) }
309+
coVerify(exactly = 1) { arrangement.checkCrlRevocationList(forceUpdate = true) }
310+
}
290311
}
291312

292313
internal class DebugDataOptionsHiltArrangement {
@@ -335,6 +356,12 @@ internal class DebugDataOptionsHiltArrangement {
335356
@MockK
336357
lateinit var setDebugE2EICertificateExpiration: SetDebugE2EICertificateExpirationUseCase
337358

359+
@MockK
360+
lateinit var observeDebugCRLExpirationAfterOneMinute: ObserveDebugCRLExpirationAfterOneMinuteUseCase
361+
362+
@MockK
363+
lateinit var setDebugCRLExpirationAfterOneMinute: SetDebugCRLExpirationAfterOneMinuteUseCase
364+
338365
private val viewModel by lazy {
339366
DebugDataOptionsViewModelImpl(
340367
context = context,
@@ -352,7 +379,9 @@ internal class DebugDataOptionsHiltArrangement {
352379
observeAsyncNotificationsEnabled = observeIsConsumableNotificationsEnabled,
353380
repairFaultyRemovalKeys = repairFaultyRemovalKeysUseCase,
354381
getDebugE2EICertificateExpiration = getDebugE2EICertificateExpiration,
355-
setDebugE2EICertificateExpiration = setDebugE2EICertificateExpiration
382+
setDebugE2EICertificateExpiration = setDebugE2EICertificateExpiration,
383+
observeDebugCRLExpirationAfterOneMinute = observeDebugCRLExpirationAfterOneMinute,
384+
setDebugCRLExpirationAfterOneMinute = setDebugCRLExpirationAfterOneMinute
356385
)
357386
}
358387

@@ -393,13 +422,19 @@ internal class DebugDataOptionsHiltArrangement {
393422
withObserveIsConsumableNotificationsEnabled(false)
394423
coEvery { getDebugE2EICertificateExpiration() } returns 360
395424
coEvery { setDebugE2EICertificateExpiration(any()) } returns Unit
425+
every { observeDebugCRLExpirationAfterOneMinute() } returns flowOf(false)
426+
coEvery { setDebugCRLExpirationAfterOneMinute(any()) } returns Unit
396427
}
397428
}
398429

399430
fun withDebugE2EICertificateExpiration(expiration: Long) = apply {
400431
coEvery { getDebugE2EICertificateExpiration() } returns expiration
401432
}
402433

434+
fun withDebugCRLExpirationAfterOneMinute(enabled: Boolean) = apply {
435+
every { observeDebugCRLExpirationAfterOneMinute() } returns flowOf(enabled)
436+
}
437+
403438
suspend fun withObserveIsConsumableNotificationsEnabled(isEnabled: Boolean = false) = apply {
404439
coEvery {
405440
observeIsConsumableNotificationsEnabled()

0 commit comments

Comments
 (0)