Skip to content
Snippets Groups Projects
Unverified Commit f138f228 authored by Mohamed Metwalli's avatar Mohamed Metwalli
Browse files

Merge branch 'release/1.15.x' into dev/merge-1.15-into-2.0

parents 7fb72e06 c801f02c
No related branches found
No related tags found
No related merge requests found
Showing
with 887 additions and 397 deletions
...@@ -19,7 +19,7 @@ object DiaryData { ...@@ -19,7 +19,7 @@ object DiaryData {
val DATA_ITEMS = listOf( val DATA_ITEMS = listOf(
DayOverviewItem.Data( DayOverviewItem.Data(
R.drawable.ic_contact_diary_location_item, R.drawable.ic_contact_diary_location_item,
"Rewe", "Supermarkt",
Duration.standardMinutes(30), Duration.standardMinutes(30),
attributes = null, attributes = null,
circumstances = null, circumstances = null,
...@@ -27,7 +27,7 @@ object DiaryData { ...@@ -27,7 +27,7 @@ object DiaryData {
), ),
DayOverviewItem.Data( DayOverviewItem.Data(
R.drawable.ic_contact_diary_person_item, R.drawable.ic_contact_diary_person_item,
"Andrea Steinhauer", "Erika Musterfrau",
null, null,
listOf( listOf(
R.string.contact_diary_person_encounter_duration_below_15_min, R.string.contact_diary_person_encounter_duration_below_15_min,
...@@ -89,7 +89,7 @@ object DiaryData { ...@@ -89,7 +89,7 @@ object DiaryData {
val PERSONS: List<DiaryPersonListItem> = listOf( val PERSONS: List<DiaryPersonListItem> = listOf(
DiaryPersonListItem( DiaryPersonListItem(
item = DefaultContactDiaryPerson(fullName = "Andrea Steinhauer"), item = DefaultContactDiaryPerson(fullName = "Erika Musterfrau"),
personEncounter = DefaultContactDiaryPersonEncounter( personEncounter = DefaultContactDiaryPersonEncounter(
contactDiaryPerson = DefaultContactDiaryPerson(fullName = ""), contactDiaryPerson = DefaultContactDiaryPerson(fullName = ""),
date = LocalDate.now(), date = LocalDate.now(),
...@@ -106,7 +106,7 @@ object DiaryData { ...@@ -106,7 +106,7 @@ object DiaryData {
onCircumstanceInfoClicked = {} onCircumstanceInfoClicked = {}
), ),
DiaryPersonListItem( DiaryPersonListItem(
item = DefaultContactDiaryPerson(fullName = "Constantin Frenzel"), item = DefaultContactDiaryPerson(fullName = "Max Mustermann"),
personEncounter = DefaultContactDiaryPersonEncounter( personEncounter = DefaultContactDiaryPersonEncounter(
contactDiaryPerson = DefaultContactDiaryPerson(fullName = ""), contactDiaryPerson = DefaultContactDiaryPerson(fullName = ""),
date = LocalDate.now() date = LocalDate.now()
...@@ -136,7 +136,6 @@ object DiaryData { ...@@ -136,7 +136,6 @@ object DiaryData {
phoneNumber = "+49151237865", phoneNumber = "+49151237865",
emailAddress = "max.musterman@me.com" emailAddress = "max.musterman@me.com"
), ),
DefaultContactDiaryPerson(fullName = "Erika Mustermann", emailAddress = "erika.mustermann@me.com"), DefaultContactDiaryPerson(fullName = "Erika Musterfrau", emailAddress = "erika.musterfrau@me.com")
DefaultContactDiaryPerson(fullName = "John Doe")
) )
} }
...@@ -42,7 +42,8 @@ object HomeData { ...@@ -42,7 +42,8 @@ object HomeData {
lastExposureDetectionTime = Instant.now(), lastExposureDetectionTime = Instant.now(),
lastEncounterAt = null, lastEncounterAt = null,
allowManualUpdate = false, allowManualUpdate = false,
daysWithEncounters = 0 daysWithEncounters = 0,
daysSinceInstallation = 4,
), ),
onCardClick = {}, onCardClick = {},
onUpdateClick = {} onUpdateClick = {}
...@@ -55,7 +56,8 @@ object HomeData { ...@@ -55,7 +56,8 @@ object HomeData {
lastExposureDetectionTime = Instant.now(), lastExposureDetectionTime = Instant.now(),
lastEncounterAt = Instant.now(), lastEncounterAt = Instant.now(),
allowManualUpdate = false, allowManualUpdate = false,
daysWithEncounters = 1 daysWithEncounters = 1,
daysSinceInstallation = 4
), ),
onCardClick = {}, onCardClick = {},
onUpdateClick = {} onUpdateClick = {}
......
...@@ -17,6 +17,7 @@ import de.rki.coronawarnapp.notification.ShareTestResultNotificationService ...@@ -17,6 +17,7 @@ import de.rki.coronawarnapp.notification.ShareTestResultNotificationService
import de.rki.coronawarnapp.statistics.source.StatisticsProvider import de.rki.coronawarnapp.statistics.source.StatisticsProvider
import de.rki.coronawarnapp.statistics.ui.homecards.StatisticsHomeCard import de.rki.coronawarnapp.statistics.ui.homecards.StatisticsHomeCard
import de.rki.coronawarnapp.storage.TracingRepository import de.rki.coronawarnapp.storage.TracingRepository
import de.rki.coronawarnapp.storage.TracingSettings
import de.rki.coronawarnapp.submission.SubmissionRepository import de.rki.coronawarnapp.submission.SubmissionRepository
import de.rki.coronawarnapp.submission.ui.homecards.SubmissionStateProvider import de.rki.coronawarnapp.submission.ui.homecards.SubmissionStateProvider
import de.rki.coronawarnapp.submission.ui.homecards.TestPositiveCard import de.rki.coronawarnapp.submission.ui.homecards.TestPositiveCard
...@@ -67,6 +68,7 @@ class HomeFragmentTest : BaseUITest() { ...@@ -67,6 +68,7 @@ class HomeFragmentTest : BaseUITest() {
@MockK lateinit var statisticsProvider: StatisticsProvider @MockK lateinit var statisticsProvider: StatisticsProvider
@MockK lateinit var deadmanNotificationScheduler: DeadmanNotificationScheduler @MockK lateinit var deadmanNotificationScheduler: DeadmanNotificationScheduler
@MockK lateinit var appShortcutsHelper: AppShortcutsHelper @MockK lateinit var appShortcutsHelper: AppShortcutsHelper
@MockK lateinit var tracingSettings: TracingSettings
private lateinit var homeFragmentViewModel: HomeFragmentViewModel private lateinit var homeFragmentViewModel: HomeFragmentViewModel
...@@ -256,7 +258,8 @@ class HomeFragmentTest : BaseUITest() { ...@@ -256,7 +258,8 @@ class HomeFragmentTest : BaseUITest() {
cwaSettings = cwaSettings, cwaSettings = cwaSettings,
statisticsProvider = statisticsProvider, statisticsProvider = statisticsProvider,
deadmanNotificationScheduler = deadmanNotificationScheduler, deadmanNotificationScheduler = deadmanNotificationScheduler,
appShortcutsHelper = appShortcutsHelper appShortcutsHelper = appShortcutsHelper,
tracingSettings = tracingSettings
) )
) )
......
...@@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 ...@@ -4,6 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.nearby.TracingPermissionHelper import de.rki.coronawarnapp.nearby.TracingPermissionHelper
import de.rki.coronawarnapp.storage.TracingSettings
import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.Runs import io.mockk.Runs
...@@ -31,6 +32,7 @@ class OnboardingTracingFragmentTest : BaseUITest() { ...@@ -31,6 +32,7 @@ class OnboardingTracingFragmentTest : BaseUITest() {
@MockK lateinit var interopRepo: InteroperabilityRepository @MockK lateinit var interopRepo: InteroperabilityRepository
@MockK lateinit var factory: TracingPermissionHelper.Factory @MockK lateinit var factory: TracingPermissionHelper.Factory
@MockK lateinit var tracingSettings: TracingSettings
@Rule @Rule
@JvmField @JvmField
...@@ -47,7 +49,8 @@ class OnboardingTracingFragmentTest : BaseUITest() { ...@@ -47,7 +49,8 @@ class OnboardingTracingFragmentTest : BaseUITest() {
OnboardingTracingFragmentViewModel( OnboardingTracingFragmentViewModel(
interoperabilityRepository = interopRepo, interoperabilityRepository = interopRepo,
tracingPermissionHelperFactory = factory, tracingPermissionHelperFactory = factory,
dispatcherProvider = TestDispatcherProvider() dispatcherProvider = TestDispatcherProvider(),
tracingSettings = tracingSettings
) )
) )
......
...@@ -41,6 +41,7 @@ object TracingData { ...@@ -41,6 +41,7 @@ object TracingData {
), ),
PeriodLoggedBox.Item( PeriodLoggedBox.Item(
daysSinceInstallation = 4,
tracingStatus = GeneralTracingStatus.Status.TRACING_INACTIVE tracingStatus = GeneralTracingStatus.Status.TRACING_INACTIVE
), ),
DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0) DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
...@@ -61,6 +62,7 @@ object TracingData { ...@@ -61,6 +62,7 @@ object TracingData {
lastExposureDetectionTime = Instant.now(), lastExposureDetectionTime = Instant.now(),
allowManualUpdate = false, allowManualUpdate = false,
daysWithEncounters = 0, daysWithEncounters = 0,
daysSinceInstallation = 4,
lastEncounterAt = Instant.now() lastEncounterAt = Instant.now()
) )
), ),
...@@ -70,6 +72,7 @@ object TracingData { ...@@ -70,6 +72,7 @@ object TracingData {
), ),
PeriodLoggedBox.Item( PeriodLoggedBox.Item(
daysSinceInstallation = 4,
tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
), ),
DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0) DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
...@@ -90,6 +93,7 @@ object TracingData { ...@@ -90,6 +93,7 @@ object TracingData {
lastExposureDetectionTime = Instant.now(), lastExposureDetectionTime = Instant.now(),
allowManualUpdate = false, allowManualUpdate = false,
daysWithEncounters = 1, daysWithEncounters = 1,
daysSinceInstallation = 4,
lastEncounterAt = Instant.now() lastEncounterAt = Instant.now()
) )
), ),
...@@ -99,6 +103,7 @@ object TracingData { ...@@ -99,6 +103,7 @@ object TracingData {
), ),
PeriodLoggedBox.Item( PeriodLoggedBox.Item(
daysSinceInstallation = 4,
tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
), ),
DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0) DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
...@@ -119,6 +124,7 @@ object TracingData { ...@@ -119,6 +124,7 @@ object TracingData {
lastExposureDetectionTime = Instant.now(), lastExposureDetectionTime = Instant.now(),
allowManualUpdate = false, allowManualUpdate = false,
daysWithEncounters = 2, daysWithEncounters = 2,
daysSinceInstallation = 4,
lastEncounterAt = Instant.now() lastEncounterAt = Instant.now()
) )
), ),
...@@ -128,6 +134,7 @@ object TracingData { ...@@ -128,6 +134,7 @@ object TracingData {
), ),
PeriodLoggedBox.Item( PeriodLoggedBox.Item(
daysSinceInstallation = 4,
tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
), ),
DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0) DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
...@@ -153,6 +160,7 @@ object TracingData { ...@@ -153,6 +160,7 @@ object TracingData {
), ),
BehaviorIncreasedRiskBox.Item, BehaviorIncreasedRiskBox.Item,
PeriodLoggedBox.Item( PeriodLoggedBox.Item(
daysSinceInstallation = 5,
tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
), ),
DetailsIncreasedRiskBox.Item( DetailsIncreasedRiskBox.Item(
......
...@@ -7,7 +7,6 @@ import dagger.assisted.AssistedInject ...@@ -7,7 +7,6 @@ import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings import de.rki.coronawarnapp.contactdiary.ui.ContactDiarySettings
import de.rki.coronawarnapp.environment.BuildConfigWrap import de.rki.coronawarnapp.environment.BuildConfigWrap
import de.rki.coronawarnapp.main.CWASettings import de.rki.coronawarnapp.main.CWASettings
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
...@@ -42,10 +41,10 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor( ...@@ -42,10 +41,10 @@ class DeltaOnboardingFragmentViewModel @AssistedInject constructor(
ContactDiarySettings.OnboardingStatus.NOT_ONBOARDED ContactDiarySettings.OnboardingStatus.NOT_ONBOARDED
} }
fun isDeltaOnboardingDone() = LocalData.isInteroperabilityShownAtLeastOnce fun isDeltaOnboardingDone() = settings.wasInteroperabilityShownAtLeastOnce
fun setDeltaOboardinDone(value: Boolean) { fun setDeltaOboardinDone(value: Boolean) {
LocalData.isInteroperabilityShownAtLeastOnce = value settings.wasInteroperabilityShownAtLeastOnce = value
} }
@AssistedFactory @AssistedFactory
......
...@@ -8,8 +8,7 @@ import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey ...@@ -8,8 +8,7 @@ import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
import com.google.gson.Gson import com.google.gson.Gson
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.submission.SubmissionSettings
import de.rki.coronawarnapp.submission.SubmissionRepository
import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryStorage
import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater import de.rki.coronawarnapp.submission.data.tekhistory.TEKHistoryUpdater
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
...@@ -17,7 +16,6 @@ import de.rki.coronawarnapp.util.serialization.BaseGson ...@@ -17,7 +16,6 @@ import de.rki.coronawarnapp.util.serialization.BaseGson
import de.rki.coronawarnapp.util.ui.SingleLiveEvent import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import timber.log.Timber import timber.log.Timber
...@@ -26,7 +24,7 @@ import java.util.UUID ...@@ -26,7 +24,7 @@ import java.util.UUID
class SubmissionTestFragmentViewModel @AssistedInject constructor( class SubmissionTestFragmentViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider, dispatcherProvider: DispatcherProvider,
private val tekHistoryStorage: TEKHistoryStorage, private val tekHistoryStorage: TEKHistoryStorage,
private val submissionRepository: SubmissionRepository, private val submissionSettings: SubmissionSettings,
tekHistoryUpdaterFactory: TEKHistoryUpdater.Factory, tekHistoryUpdaterFactory: TEKHistoryUpdater.Factory,
@BaseGson baseGson: Gson @BaseGson baseGson: Gson
) : CWAViewModel(dispatcherProvider = dispatcherProvider) { ) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
...@@ -60,8 +58,7 @@ class SubmissionTestFragmentViewModel @AssistedInject constructor( ...@@ -60,8 +58,7 @@ class SubmissionTestFragmentViewModel @AssistedInject constructor(
) )
val errorEvents = SingleLiveEvent<Throwable>() val errorEvents = SingleLiveEvent<Throwable>()
private val internalToken = MutableStateFlow(LocalData.registrationToken()) val currentTestId = submissionSettings.registrationToken.flow.asLiveData()
val currentTestId = internalToken.asLiveData()
val shareTEKsEvent = SingleLiveEvent<TEKExport>() val shareTEKsEvent = SingleLiveEvent<TEKExport>()
...@@ -85,13 +82,15 @@ class SubmissionTestFragmentViewModel @AssistedInject constructor( ...@@ -85,13 +82,15 @@ class SubmissionTestFragmentViewModel @AssistedInject constructor(
.asLiveData(context = dispatcherProvider.Default) .asLiveData(context = dispatcherProvider.Default)
fun scrambleRegistrationToken() { fun scrambleRegistrationToken() {
LocalData.registrationToken(UUID.randomUUID().toString()) submissionSettings.registrationToken.update {
internalToken.value = LocalData.registrationToken() UUID.randomUUID().toString()
}
} }
fun deleteRegistrationToken() { fun deleteRegistrationToken() {
LocalData.registrationToken(null) submissionSettings.registrationToken.update {
internalToken.value = LocalData.registrationToken() null
}
} }
fun updateStorage() { fun updateStorage() {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -21,7 +21,9 @@ import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver ...@@ -21,7 +21,9 @@ import de.rki.coronawarnapp.exception.reporting.ErrorReportReceiver
import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL import de.rki.coronawarnapp.exception.reporting.ReportingConstants.ERROR_REPORT_LOCAL_BROADCAST_CHANNEL
import de.rki.coronawarnapp.notification.NotificationHelper import de.rki.coronawarnapp.notification.NotificationHelper
import de.rki.coronawarnapp.risk.RiskLevelChangeDetector import de.rki.coronawarnapp.risk.RiskLevelChangeDetector
import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.submission.SubmissionSettings
import de.rki.coronawarnapp.storage.OnboardingSettings
import de.rki.coronawarnapp.storage.preferences.EncryptedPreferencesMigration
import de.rki.coronawarnapp.submission.auto.AutoSubmission import de.rki.coronawarnapp.submission.auto.AutoSubmission
import de.rki.coronawarnapp.task.TaskController import de.rki.coronawarnapp.task.TaskController
import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.CWADebug
...@@ -29,6 +31,7 @@ import de.rki.coronawarnapp.util.WatchdogService ...@@ -29,6 +31,7 @@ import de.rki.coronawarnapp.util.WatchdogService
import de.rki.coronawarnapp.util.device.ForegroundState import de.rki.coronawarnapp.util.device.ForegroundState
import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.di.AppInjector
import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.util.di.ApplicationComponent
import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
...@@ -57,6 +60,9 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { ...@@ -57,6 +60,9 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
@Inject lateinit var notificationHelper: NotificationHelper @Inject lateinit var notificationHelper: NotificationHelper
@Inject lateinit var deviceTimeHandler: DeviceTimeHandler @Inject lateinit var deviceTimeHandler: DeviceTimeHandler
@Inject lateinit var autoSubmission: AutoSubmission @Inject lateinit var autoSubmission: AutoSubmission
@Inject lateinit var submissionSettings: SubmissionSettings
@Inject lateinit var onboardingSettings: OnboardingSettings
@Inject lateinit var encryptedPreferencesMigration: EncryptedPreferencesMigration
@LogHistoryTree @Inject lateinit var rollingLogHistory: Timber.Tree @LogHistoryTree @Inject lateinit var rollingLogHistory: Timber.Tree
...@@ -70,6 +76,10 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { ...@@ -70,6 +76,10 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
CWADebug.initAfterInjection(component) CWADebug.initAfterInjection(component)
encryptedPreferencesMigration.doMigration()
BackgroundWorkScheduler.init(component)
Timber.plant(rollingLogHistory) Timber.plant(rollingLogHistory)
Timber.v("onCreate(): WorkManager setup done: $workManager") Timber.v("onCreate(): WorkManager setup done: $workManager")
...@@ -87,8 +97,8 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { ...@@ -87,8 +97,8 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
.onEach { isAppInForeground = it } .onEach { isAppInForeground = it }
.launchIn(GlobalScope) .launchIn(GlobalScope)
if (LocalData.onboardingCompletedTimestamp() != null) { if (onboardingSettings.isOnboarded) {
if (!LocalData.isAllowedToSubmitDiagnosisKeys()) { if (!submissionSettings.isAllowedToSubmitKeys) {
deadmanNotificationScheduler.schedulePeriodic() deadmanNotificationScheduler.schedulePeriodic()
} }
contactDiaryWorkScheduler.schedulePeriodic() contactDiaryWorkScheduler.schedulePeriodic()
......
...@@ -3,9 +3,12 @@ package de.rki.coronawarnapp.bugreporting ...@@ -3,9 +3,12 @@ package de.rki.coronawarnapp.bugreporting
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.Reusable import dagger.Reusable
import dagger.multibindings.IntoSet
import de.rki.coronawarnapp.bugreporting.censors.BugCensor import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryEncounterCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryLocationCensor import de.rki.coronawarnapp.bugreporting.censors.DiaryLocationCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryPersonCensor import de.rki.coronawarnapp.bugreporting.censors.DiaryPersonCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryVisitCensor
import de.rki.coronawarnapp.bugreporting.censors.QRCodeCensor import de.rki.coronawarnapp.bugreporting.censors.QRCodeCensor
import de.rki.coronawarnapp.bugreporting.censors.RegistrationTokenCensor import de.rki.coronawarnapp.bugreporting.censors.RegistrationTokenCensor
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope
...@@ -22,7 +25,6 @@ import okhttp3.OkHttpClient ...@@ -22,7 +25,6 @@ import okhttp3.OkHttpClient
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.protobuf.ProtoConverterFactory import retrofit2.converter.protobuf.ProtoConverterFactory
import timber.log.Timber
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
...@@ -67,19 +69,27 @@ class BugReportingSharedModule { ...@@ -67,19 +69,27 @@ class BugReportingSharedModule {
@Provides @Provides
fun scope(): CoroutineScope = DebugLoggerScope fun scope(): CoroutineScope = DebugLoggerScope
@Singleton
@Provides @Provides
fun censors( @IntoSet
registrationTokenCensor: RegistrationTokenCensor, fun registrationTokenCensor(censor: RegistrationTokenCensor): BugCensor = censor
diaryPersonCensor: DiaryPersonCensor,
diaryLocationCensor: DiaryLocationCensor, @Provides
qrCodeCensor: QRCodeCensor @IntoSet
): List<BugCensor> = listOf( fun qrCodeCensor(censor: QRCodeCensor): BugCensor = censor
registrationTokenCensor,
diaryPersonCensor, @Provides
diaryLocationCensor, @IntoSet
qrCodeCensor fun diaryPersonCensor(censor: DiaryPersonCensor): BugCensor = censor
).also {
Timber.d("Loaded BugCensors: %s", it) @Provides
} @IntoSet
fun diaryEncounterCensor(censor: DiaryEncounterCensor): BugCensor = censor
@Provides
@IntoSet
fun diaryLocationCensor(censor: DiaryLocationCensor): BugCensor = censor
@Provides
@IntoSet
fun diaryVisitCensor(censor: DiaryVisitCensor): BugCensor = censor
} }
...@@ -8,4 +8,38 @@ interface BugCensor { ...@@ -8,4 +8,38 @@ interface BugCensor {
* If there is something to censor a new log line is returned, otherwise returns null * If there is something to censor a new log line is returned, otherwise returns null
*/ */
suspend fun checkLog(entry: LogLine): LogLine? suspend fun checkLog(entry: LogLine): LogLine?
companion object {
fun withValidName(name: String?, action: (String) -> Unit): Boolean {
if (name.isNullOrBlank()) return false
if (name.length < 3) return false
action(name)
return true
}
fun withValidEmail(email: String?, action: (String) -> Unit): Boolean {
if (email.isNullOrBlank()) return false
if (email.length < 6) return false
action(email)
return true
}
fun withValidPhoneNumber(number: String?, action: (String) -> Unit): Boolean {
if (number.isNullOrBlank()) return false
if (number.length < 4) return false
action(number)
return true
}
fun withValidComment(comment: String?, action: (String) -> Unit): Boolean {
if (comment.isNullOrBlank()) return false
if (comment.length < 3) return false
action(comment)
return true
}
fun LogLine.toNewLogLineIfDifferent(newMessage: String): LogLine? {
return if (newMessage != message) copy(message = newMessage) else null
}
}
} }
package de.rki.coronawarnapp.bugreporting.censors
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidComment
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject
@Reusable
class DiaryEncounterCensor @Inject constructor(
@DebuggerScope debugScope: CoroutineScope,
diary: ContactDiaryRepository
) : BugCensor {
private val encounters by lazy {
diary.personEncounters.stateIn(
scope = debugScope,
started = SharingStarted.Lazily,
initialValue = null
).filterNotNull()
}
override suspend fun checkLog(entry: LogLine): LogLine? {
val encountersNow = encounters.first().filter { !it.circumstances.isNullOrBlank() }
if (encountersNow.isEmpty()) return null
val newMessage = encountersNow.fold(entry.message) { orig, encounter ->
var wip = orig
withValidComment(encounter.circumstances) {
wip = wip.replace(it, "Encounter#${encounter.id}/Circumstances")
}
wip
}
return entry.toNewLogLineIfDifferent(newMessage)
}
}
package de.rki.coronawarnapp.bugreporting.censors package de.rki.coronawarnapp.bugreporting.censors
import dagger.Reusable import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEmail
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
import de.rki.coronawarnapp.util.CWADebug
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
...@@ -31,14 +34,22 @@ class DiaryLocationCensor @Inject constructor( ...@@ -31,14 +34,22 @@ class DiaryLocationCensor @Inject constructor(
if (locationsNow.isEmpty()) return null if (locationsNow.isEmpty()) return null
var newMessage = locationsNow.fold(entry.message) { oldMsg, location -> val newMessage = locationsNow.fold(entry.message) { orig, location ->
oldMsg.replace(location.locationName, "Location#${location.locationId}") var wip = orig
}
withValidName(location.locationName) {
wip = wip.replace(it, "Location#${location.locationId}/Name")
}
withValidEmail(location.emailAddress) {
wip = wip.replace(it, "Location#${location.locationId}/EMail")
}
withValidPhoneNumber(location.phoneNumber) {
wip = wip.replace(it, "Location#${location.locationId}/PhoneNumber")
}
if (CWADebug.isDeviceForTestersBuild) { wip
newMessage = entry.message
} }
return entry.copy(message = newMessage) return entry.toNewLogLineIfDifferent(newMessage)
} }
} }
package de.rki.coronawarnapp.bugreporting.censors package de.rki.coronawarnapp.bugreporting.censors
import dagger.Reusable import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEmail
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
import de.rki.coronawarnapp.util.CWADebug
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
...@@ -31,14 +34,22 @@ class DiaryPersonCensor @Inject constructor( ...@@ -31,14 +34,22 @@ class DiaryPersonCensor @Inject constructor(
if (personsNow.isEmpty()) return null if (personsNow.isEmpty()) return null
var newMessage = personsNow.fold(entry.message) { oldMsg, person -> val newMessage = personsNow.fold(entry.message) { orig, person ->
oldMsg.replace(person.fullName, "Person#${person.personId}") var wip = orig
}
withValidName(person.fullName) {
wip = wip.replace(it, "Person#${person.personId}/Name")
}
withValidEmail(person.emailAddress) {
wip = wip.replace(it, "Person#${person.personId}/EMail")
}
withValidPhoneNumber(person.phoneNumber) {
wip = wip.replace(it, "Person#${person.personId}/PhoneNumber")
}
if (CWADebug.isDeviceForTestersBuild) { wip
newMessage = entry.message
} }
return entry.copy(message = newMessage) return entry.toNewLogLineIfDifferent(newMessage)
} }
} }
package de.rki.coronawarnapp.bugreporting.censors
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject
@Reusable
class DiaryVisitCensor @Inject constructor(
@DebuggerScope debugScope: CoroutineScope,
diary: ContactDiaryRepository
) : BugCensor {
private val visits by lazy {
diary.locationVisits.stateIn(
scope = debugScope,
started = SharingStarted.Lazily,
initialValue = null
).filterNotNull()
}
override suspend fun checkLog(entry: LogLine): LogLine? {
val visitsNow = visits.first().filter { !it.circumstances.isNullOrBlank() }
if (visitsNow.isEmpty()) return null
val newMessage = visitsNow.fold(entry.message) { orig, visit ->
var wip = orig
BugCensor.withValidComment(visit.circumstances) {
wip = wip.replace(it, "Visit#${visit.id}/Circumstances")
}
wip
}
return entry.toNewLogLineIfDifferent(newMessage)
}
}
package de.rki.coronawarnapp.bugreporting.censors package de.rki.coronawarnapp.bugreporting.censors
import dagger.Reusable import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.CWADebug
import javax.inject.Inject import javax.inject.Inject
...@@ -13,17 +14,18 @@ class QRCodeCensor @Inject constructor() : BugCensor { ...@@ -13,17 +14,18 @@ class QRCodeCensor @Inject constructor() : BugCensor {
val guid = lastGUID ?: return null val guid = lastGUID ?: return null
if (!entry.message.contains(guid)) return null if (!entry.message.contains(guid)) return null
var newMessage = entry.message.replace(guid, PLACEHOLDER + guid.takeLast(4)) val newMessage = if (CWADebug.isDeviceForTestersBuild) {
entry.message.replace(guid, PLACEHOLDER_TESTER + guid.takeLast(27))
if (CWADebug.isDeviceForTestersBuild) { } else {
newMessage = entry.message entry.message.replace(guid, PLACEHOLDER + guid.takeLast(4))
} }
return entry.copy(message = newMessage) return entry.toNewLogLineIfDifferent(newMessage)
} }
companion object { companion object {
var lastGUID: String? = null var lastGUID: String? = null
private const val PLACEHOLDER_TESTER = "########-"
private const val PLACEHOLDER = "########-####-####-####-########" private const val PLACEHOLDER = "########-####-####-####-########"
} }
} }
package de.rki.coronawarnapp.bugreporting.censors package de.rki.coronawarnapp.bugreporting.censors
import dagger.Reusable import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.submission.SubmissionSettings
import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.CWADebug
import javax.inject.Inject import javax.inject.Inject
@Reusable @Reusable
class RegistrationTokenCensor @Inject constructor() : BugCensor { class RegistrationTokenCensor @Inject constructor(
private val submissionSettings: SubmissionSettings
) : BugCensor {
override suspend fun checkLog(entry: LogLine): LogLine? { override suspend fun checkLog(entry: LogLine): LogLine? {
val token = LocalData.registrationToken() ?: return null val token = submissionSettings.registrationToken.value ?: return null
if (!entry.message.contains(token)) return null if (!entry.message.contains(token)) return null
var newMessage = entry.message.replace(token, PLACEHOLDER + token.takeLast(4)) val newMessage = if (CWADebug.isDeviceForTestersBuild) {
entry.message.replace(token, PLACEHOLDER_TESTER + token.takeLast(27))
if (CWADebug.isDeviceForTestersBuild) { } else {
newMessage = entry.message entry.message.replace(token, PLACEHOLDER + token.takeLast(4))
} }
return entry.copy(message = newMessage) return entry.toNewLogLineIfDifferent(newMessage)
} }
companion object { companion object {
private const val PLACEHOLDER_TESTER = "########-"
private const val PLACEHOLDER = "########-####-####-####-########" private const val PLACEHOLDER = "########-####-####-####-########"
} }
} }
...@@ -90,6 +90,7 @@ class DebugLogger( ...@@ -90,6 +90,7 @@ class DebugLogger(
Timber.tag(TAG).i("setInjectionIsReady()") Timber.tag(TAG).i("setInjectionIsReady()")
component.inject(this) component.inject(this)
isDaggerReady = true isDaggerReady = true
Timber.tag(TAG).d("Censors loaded: %s", bugCensors)
} }
suspend fun start(): Unit = mutex.withLock { suspend fun start(): Unit = mutex.withLock {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment