feat(user-recovery): Added User Recovery modules.
Added GetRecoveryFile/GetRecoveryPrivateKeys. Added GetRecoveryInactivePrivateKeys. Added DeviceRecoveryHandler/DeviceRecoveryHandlerInitializer.
This commit is contained in:
parent
f765277259
commit
db6de90587
|
@ -232,6 +232,13 @@ Core libraries coordinates can be found under [coordinates section](#coordinates
|
|||
| me.proton.core:user-dagger |
|
||||
| me.proton.core:user-data |
|
||||
| me.proton.core:user-domain |
|
||||
| me.proton.core:user-recovery |
|
||||
| me.proton.core:user-recovery-dagger |
|
||||
| me.proton.core:user-recovery-data |
|
||||
| me.proton.core:user-recovery-domain |
|
||||
| me.proton.core:user-recovery-presentation |
|
||||
| me.proton.core:user-recovery-presentation-compose |
|
||||
| me.proton.core:user-recovery-test |
|
||||
| me.proton.core:user-settings |
|
||||
| me.proton.core:user-settings-dagger |
|
||||
| me.proton.core:user-settings-data |
|
||||
|
|
|
@ -233,6 +233,7 @@ dependencies {
|
|||
project(Module.report),
|
||||
project(Module.telemetry),
|
||||
project(Module.user),
|
||||
project(Module.userRecovery),
|
||||
project(Module.userSettings),
|
||||
project(Module.strictModeUtil),
|
||||
project(Module.keyTransparency),
|
||||
|
|
|
@ -99,6 +99,10 @@
|
|||
android:name="me.proton.core.paymentiap.presentation.GooglePurchaseHandlerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
<meta-data
|
||||
android:name="me.proton.core.userrecovery.presentation.DeviceRecoveryHandlerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
|
|
|
@ -35,6 +35,7 @@ import me.proton.core.network.presentation.init.UnAuthSessionFetcherInitializer
|
|||
import me.proton.core.paymentiap.presentation.GooglePurchaseHandlerInitializer
|
||||
import me.proton.core.plan.presentation.PurchaseHandlerInitializer
|
||||
import me.proton.core.plan.presentation.UnredeemedPurchaseInitializer
|
||||
import me.proton.core.userrecovery.presentation.DeviceRecoveryHandlerInitializer
|
||||
|
||||
@HiltAndroidApp
|
||||
class CoreExampleApp : Application() {
|
||||
|
@ -44,6 +45,7 @@ class CoreExampleApp : Application() {
|
|||
initializeComponent(WorkManagerInitializer::class.java)
|
||||
initializeComponent(EventManagerInitializer::class.java)
|
||||
initializeComponent(AccountStateHandlerInitializer::class.java)
|
||||
initializeComponent(DeviceRecoveryHandlerInitializer::class.java)
|
||||
initializeComponent(CryptoValidatorInitializer::class.java)
|
||||
initializeComponent(PurchaseHandlerInitializer::class.java)
|
||||
initializeComponent(GooglePurchaseHandlerInitializer::class.java)
|
||||
|
|
|
@ -176,6 +176,14 @@ public object Module {
|
|||
public const val countryDomain: String = "$country:country-domain"
|
||||
public const val countryPresentation: String = "$country:country-presentation"
|
||||
|
||||
// User Recovery
|
||||
public const val userRecovery: String = ":user-recovery"
|
||||
public const val userRecoveryDagger: String = "$userRecovery:user-recovery-dagger"
|
||||
public const val userRecoveryData: String = "$userRecovery:user-recovery-data"
|
||||
public const val userRecoveryDomain: String = "$userRecovery:user-recovery-domain"
|
||||
public const val userRecoveryPresentation: String = "$userRecovery:user-recovery-presentation"
|
||||
public const val userRecoveryPresentationCompose: String = "$userRecovery:user-recovery-presentation-compose"
|
||||
|
||||
// Settings
|
||||
public const val userSettings: String = ":user-settings"
|
||||
public const val userSettingsDagger: String = "$userSettings:user-settings-dagger"
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
}
|
||||
|
||||
protonCoverage.disabled.set(true)
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.userrecovery"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.userRecoveryDagger),
|
||||
project(Module.userRecoveryData),
|
||||
project(Module.userRecoveryDomain),
|
||||
project(Module.userRecoveryPresentation),
|
||||
project(Module.userRecoveryPresentationCompose)
|
||||
)
|
||||
}
|
||||
|
||||
dependencyAnalysis.issues { onAny { severity("ignore") } }
|
|
@ -0,0 +1,15 @@
|
|||
public class hilt_aggregated_deps/_me_proton_core_userrecovery_dagger_CoreDeviceRecoveryModule {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/dagger/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/dagger/CoreDeviceRecoveryModule {
|
||||
public static final field INSTANCE Lme/proton/core/userrecovery/dagger/CoreDeviceRecoveryModule;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
protonDagger
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.userrecovery.dagger"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.userRecoveryData),
|
||||
project(Module.userRecoveryDomain),
|
||||
)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.dagger
|
||||
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
public object CoreDeviceRecoveryModule {
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
public class hilt_aggregated_deps/_me_proton_core_userrecovery_data_worker_SetRecoverySecretWorker_HiltModule {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/DeviceRecoveryHandler {
|
||||
public fun <init> (Lme/proton/core/util/kotlin/CoroutineScopeProvider;Lme/proton/core/crypto/common/context/CryptoContext;Lme/proton/core/accountmanager/domain/AccountManager;Lme/proton/core/user/domain/UserManager;Lme/proton/core/userrecovery/domain/usecase/GetRecoveryFile;Lme/proton/core/userrecovery/domain/usecase/GetRecoveryPrivateKeys;Lme/proton/core/userrecovery/domain/usecase/GetRecoveryInactivePrivateKeys;)V
|
||||
public final fun start ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/DeviceRecoveryHandler_Factory : dagger/internal/Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lme/proton/core/userrecovery/data/DeviceRecoveryHandler_Factory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/userrecovery/data/DeviceRecoveryHandler;
|
||||
public static fun newInstance (Lme/proton/core/util/kotlin/CoroutineScopeProvider;Lme/proton/core/crypto/common/context/CryptoContext;Lme/proton/core/accountmanager/domain/AccountManager;Lme/proton/core/user/domain/UserManager;Lme/proton/core/userrecovery/domain/usecase/GetRecoveryFile;Lme/proton/core/userrecovery/domain/usecase/GetRecoveryPrivateKeys;Lme/proton/core/userrecovery/domain/usecase/GetRecoveryInactivePrivateKeys;)Lme/proton/core/userrecovery/data/DeviceRecoveryHandler;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl : me/proton/core/userrecovery/domain/IsDeviceRecoveryEnabled {
|
||||
public static final field Companion Lme/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl$Companion;
|
||||
public fun <init> (Landroid/content/Context;Lme/proton/core/featureflag/domain/FeatureFlagManager;)V
|
||||
public fun invoke (Lme/proton/core/domain/entity/UserId;)Z
|
||||
public fun isLocalEnabled ()Z
|
||||
public fun isRemoteEnabled (Lme/proton/core/domain/entity/UserId;)Z
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl$Companion {
|
||||
public final fun getFeatureId ()Lme/proton/core/featureflag/domain/entity/FeatureId;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl_Factory : dagger/internal/Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;)Lme/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl_Factory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl;
|
||||
public static fun newInstance (Landroid/content/Context;Lme/proton/core/featureflag/domain/FeatureFlagManager;)Lme/proton/core/userrecovery/data/IsDeviceRecoveryEnabledImpl;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker : androidx/work/CoroutineWorker {
|
||||
public static final field Companion Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker$Companion;
|
||||
public fun <init> (Landroid/content/Context;Landroidx/work/WorkerParameters;Lme/proton/core/userrecovery/domain/usecase/SetRecoverySecretRemote;)V
|
||||
public fun doWork (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun getContext ()Landroid/content/Context;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker$Companion {
|
||||
public final fun getRequest (Lme/proton/core/domain/entity/UserId;)Landroidx/work/OneTimeWorkRequest;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_AssistedFactory : androidx/hilt/work/WorkerAssistedFactory {
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_AssistedFactory_Impl : me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_AssistedFactory {
|
||||
public synthetic fun create (Landroid/content/Context;Landroidx/work/WorkerParameters;)Landroidx/work/ListenableWorker;
|
||||
public fun create (Landroid/content/Context;Landroidx/work/WorkerParameters;)Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker;
|
||||
public static fun create (Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_Factory;)Ljavax/inject/Provider;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;)Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_Factory;
|
||||
public fun get (Landroid/content/Context;Landroidx/work/WorkerParameters;)Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker;
|
||||
public static fun newInstance (Landroid/content/Context;Landroidx/work/WorkerParameters;Lme/proton/core/userrecovery/domain/usecase/SetRecoverySecretRemote;)Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_HiltModule {
|
||||
public abstract fun bind (Lme/proton/core/userrecovery/data/worker/SetRecoverySecretWorker_AssistedFactory;)Landroidx/hilt/work/WorkerAssistedFactory;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/worker/UserRecoveryWorkerManagerImpl : me/proton/core/userrecovery/domain/worker/UserRecoveryWorkerManager {
|
||||
public fun <init> (Landroidx/work/WorkManager;)V
|
||||
public fun enqueueSetRecoverySecret (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/data/worker/UserRecoveryWorkerManagerImpl_Factory : dagger/internal/Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;)Lme/proton/core/userrecovery/data/worker/UserRecoveryWorkerManagerImpl_Factory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/userrecovery/data/worker/UserRecoveryWorkerManagerImpl;
|
||||
public static fun newInstance (Landroidx/work/WorkManager;)Lme/proton/core/userrecovery/data/worker/UserRecoveryWorkerManagerImpl;
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import studio.forface.easygradle.dsl.*
|
||||
import studio.forface.easygradle.dsl.android.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
protonDagger
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
protonBuild {
|
||||
apiModeDisabled()
|
||||
}
|
||||
|
||||
protonCoverage {
|
||||
branchCoveragePercentage.set(71)
|
||||
lineCoveragePercentage.set(68)
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
protonDagger {
|
||||
workManagerHiltIntegration = true
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.userrecovery.data"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.domain),
|
||||
project(Module.userRecoveryDomain),
|
||||
project(Module.eventManagerDomain),
|
||||
`android-work-runtime`,
|
||||
`coroutines-core`,
|
||||
`javax-inject`,
|
||||
retrofit,
|
||||
`serialization-core`
|
||||
)
|
||||
|
||||
implementation(
|
||||
project(Module.data),
|
||||
project(Module.kotlinUtil),
|
||||
project(Module.userData)
|
||||
)
|
||||
|
||||
testImplementation(
|
||||
project(Module.androidTest),
|
||||
project(Module.kotlinTest),
|
||||
`android-work-testing`,
|
||||
`coroutines-test`,
|
||||
`hilt-android-testing`,
|
||||
junit,
|
||||
`kotlin-test`,
|
||||
mockk,
|
||||
robolectric
|
||||
)
|
||||
|
||||
kaptTest(`hilt-android-compiler`)
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.data
|
||||
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import me.proton.core.accountmanager.domain.AccountManager
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.userrecovery.domain.LogTag
|
||||
import me.proton.core.userrecovery.domain.usecase.GetRecoveryFile
|
||||
import me.proton.core.userrecovery.domain.usecase.GetRecoveryInactivePrivateKeys
|
||||
import me.proton.core.userrecovery.domain.usecase.GetRecoveryPrivateKeys
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import me.proton.core.util.kotlin.CoroutineScopeProvider
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class DeviceRecoveryHandler @Inject constructor(
|
||||
internal val scopeProvider: CoroutineScopeProvider,
|
||||
internal val cryptoContext: CryptoContext,
|
||||
internal val accountManager: AccountManager,
|
||||
internal val userManager: UserManager,
|
||||
internal val getRecoveryFile: GetRecoveryFile,
|
||||
internal val getRecoveryPrivateKeys: GetRecoveryPrivateKeys,
|
||||
internal val getRecoveryInactivePrivateKeys: GetRecoveryInactivePrivateKeys,
|
||||
) {
|
||||
fun start() {
|
||||
scopeProvider.GlobalDefaultSupervisedScope.launch {
|
||||
val userId = accountManager.getPrimaryUserId().firstOrNull() ?: return@launch
|
||||
|
||||
val message = getRecoveryFile(userId)
|
||||
CoreLogger.d(LogTag.DEFAULT, "Recovery file: $message")
|
||||
val keys = getRecoveryPrivateKeys(userId, message)
|
||||
CoreLogger.d(LogTag.DEFAULT, "Recovery Private Keys: $keys")
|
||||
val recoverable = getRecoveryInactivePrivateKeys(userId, keys)
|
||||
CoreLogger.d(LogTag.DEFAULT, "Recovery inactive keys: $recoverable")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* Copyright (c) 2024 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.data
|
||||
package me.proton.core.userrecovery.data
|
||||
|
||||
import android.content.Context
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
|
@ -24,7 +24,7 @@ import me.proton.core.domain.entity.UserId
|
|||
import me.proton.core.featureflag.domain.ExperimentalProtonFeatureFlag
|
||||
import me.proton.core.featureflag.domain.FeatureFlagManager
|
||||
import me.proton.core.featureflag.domain.entity.FeatureId
|
||||
import me.proton.core.usersettings.domain.IsDeviceRecoveryEnabled
|
||||
import me.proton.core.userrecovery.domain.IsDeviceRecoveryEnabled
|
||||
import javax.inject.Inject
|
||||
|
||||
class IsDeviceRecoveryEnabledImpl @Inject constructor(
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.data.worker
|
||||
package me.proton.core.userrecovery.data.worker
|
||||
|
||||
import android.content.Context
|
||||
import androidx.hilt.work.HiltWorker
|
||||
|
@ -32,8 +32,8 @@ import dagger.assisted.AssistedInject
|
|||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.network.domain.ApiException
|
||||
import me.proton.core.network.domain.isRetryable
|
||||
import me.proton.core.usersettings.domain.LogTag
|
||||
import me.proton.core.usersettings.domain.usecase.SetRecoverySecretRemote
|
||||
import me.proton.core.userrecovery.domain.usecase.SetRecoverySecretRemote
|
||||
import me.proton.core.userrecovery.domain.LogTag
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
|
||||
@HiltWorker
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.data.worker
|
||||
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.WorkManager
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.userrecovery.domain.worker.UserRecoveryWorkerManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class UserRecoveryWorkerManagerImpl @Inject constructor(
|
||||
private val workManager: WorkManager
|
||||
) : UserRecoveryWorkerManager {
|
||||
|
||||
override suspend fun enqueueSetRecoverySecret(userId: UserId) {
|
||||
workManager.enqueueUniqueWork(
|
||||
"setRecoverySecretWork-${userId.id}",
|
||||
ExistingWorkPolicy.KEEP,
|
||||
SetRecoverySecretWorker.getRequest(userId)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.data
|
||||
package me.proton.core.userrecovery.data
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.data.worker
|
||||
package me.proton.core.userrecovery.data.worker
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
|
@ -30,7 +30,7 @@ import kotlinx.coroutines.test.runTest
|
|||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.network.domain.ApiException
|
||||
import me.proton.core.network.domain.ApiResult
|
||||
import me.proton.core.usersettings.domain.usecase.SetRecoverySecretRemote
|
||||
import me.proton.core.userrecovery.domain.usecase.SetRecoverySecretRemote
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.data.worker
|
||||
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class UserRecoveryWorkerManagerImplTest {
|
||||
|
||||
private val testUserId = "test-user-id"
|
||||
|
||||
private val workManager = mockk<WorkManager>(relaxed = true)
|
||||
|
||||
private lateinit var tested: UserRecoveryWorkerManagerImpl
|
||||
|
||||
@Before
|
||||
fun beforeEveryTest() {
|
||||
tested = UserRecoveryWorkerManagerImpl(workManager)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setRecoverySecret() = runTest {
|
||||
// WHEN
|
||||
tested.enqueueSetRecoverySecret(UserId(testUserId))
|
||||
// THEN
|
||||
verify {
|
||||
workManager.enqueueUniqueWork(
|
||||
"setRecoverySecretWork-test-user-id",
|
||||
ExistingWorkPolicy.KEEP,
|
||||
any<OneTimeWorkRequest>()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
public abstract interface class me/proton/core/userrecovery/domain/IsDeviceRecoveryEnabled {
|
||||
public abstract fun invoke (Lme/proton/core/domain/entity/UserId;)Z
|
||||
public abstract fun isLocalEnabled ()Z
|
||||
public abstract fun isRemoteEnabled (Lme/proton/core/domain/entity/UserId;)Z
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/LogTag {
|
||||
public static final field DEFAULT Ljava/lang/String;
|
||||
public static final field INSTANCE Lme/proton/core/userrecovery/domain/LogTag;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/ByteArrayList {
|
||||
public static final field Companion Lme/proton/core/userrecovery/domain/usecase/ByteArrayList$Companion;
|
||||
public fun <init> (Ljava/util/List;)V
|
||||
public final fun component1 ()Ljava/util/List;
|
||||
public final fun copy (Ljava/util/List;)Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;
|
||||
public static synthetic fun copy$default (Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;Ljava/util/List;ILjava/lang/Object;)Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getKeys ()Ljava/util/List;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/ByteArrayList$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lme/proton/core/userrecovery/domain/usecase/ByteArrayList$$serializer;
|
||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;
|
||||
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/ByteArrayList$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/GetRecoveryFile {
|
||||
public fun <init> (Lme/proton/core/user/domain/UserManager;Lme/proton/core/crypto/common/context/CryptoContext;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/GetRecoveryInactivePrivateKeys {
|
||||
public fun <init> (Lme/proton/core/user/domain/UserManager;Lme/proton/core/crypto/common/context/CryptoContext;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/GetRecoveryPrivateKeys {
|
||||
public fun <init> (Lme/proton/core/user/domain/UserManager;Lme/proton/core/user/domain/repository/PassphraseRepository;Lme/proton/core/crypto/common/context/CryptoContext;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/GetRecoverySecret {
|
||||
public fun <init> (Lme/proton/core/user/domain/UserManager;Lme/proton/core/crypto/common/context/CryptoContext;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/SetRecoverySecretRemote {
|
||||
public fun <init> (Lme/proton/core/eventmanager/domain/EventManagerProvider;Lme/proton/core/userrecovery/domain/usecase/GetRecoverySecret;Lme/proton/core/usersettings/domain/repository/UserSettingsRemoteDataSource;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/userrecovery/domain/worker/UserRecoveryWorkerManager {
|
||||
public abstract fun enqueueSetRecoverySecret (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonKotlinLibrary
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
protonBuild {
|
||||
apiModeDisabled()
|
||||
}
|
||||
|
||||
protonCoverage {
|
||||
disabled.set(true)
|
||||
//branchCoveragePercentage.set(38)
|
||||
//lineCoveragePercentage.set(71)
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.domain),
|
||||
project(Module.keyDomain),
|
||||
project(Module.userDomain),
|
||||
project(Module.userSettingsDomain),
|
||||
project(Module.cryptoCommon),
|
||||
project(Module.eventManagerDomain),
|
||||
`coroutines-core`,
|
||||
`javax-inject`,
|
||||
)
|
||||
|
||||
implementation(
|
||||
project(Module.kotlinUtil),
|
||||
`serialization-json`
|
||||
)
|
||||
|
||||
testImplementation(
|
||||
project(Module.kotlinTest),
|
||||
`coroutines-test`,
|
||||
junit,
|
||||
`kotlin-test`,
|
||||
mockk
|
||||
)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.domain
|
||||
package me.proton.core.userrecovery.domain
|
||||
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain
|
||||
|
||||
object LogTag {
|
||||
/** Default tag for any other issue we need to log */
|
||||
const val DEFAULT = "core.userrecovery.default"
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.pgp.EncryptedMessage
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.key.domain.unlockOrNull
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.util.kotlin.serialize
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Generate a recovery file encrypted with primary recovery secret.
|
||||
*/
|
||||
class GetRecoveryFile @Inject constructor(
|
||||
private val userManager: UserManager,
|
||||
private val cryptoContext: CryptoContext
|
||||
) {
|
||||
private val pgpCrypto = cryptoContext.pgpCrypto
|
||||
|
||||
suspend operator fun invoke(
|
||||
userId: UserId
|
||||
): EncryptedMessage {
|
||||
val user = userManager.getUser(userId)
|
||||
val primaryKey = user.keys.firstOrNull { it.privateKey.isPrimary }
|
||||
val primaryKeyRecoverySecret = requireNotNull(primaryKey?.recoverySecret)
|
||||
val activeKeys = user.keys.filter { it.active ?: false }
|
||||
val privateKeys = activeKeys.map { it.privateKey }
|
||||
val unlockedKeys = privateKeys.mapNotNull { it.unlockOrNull(cryptoContext)?.unlockedKey }
|
||||
check(unlockedKeys.isNotEmpty())
|
||||
val byteArrayList = ByteArrayList(unlockedKeys.map { it.value })
|
||||
val fileByteArray = byteArrayList.serialize().encodeToByteArray()
|
||||
val secret = pgpCrypto.getBase64Decoded(primaryKeyRecoverySecret)
|
||||
return pgpCrypto.encryptDataWithPassword(fileByteArray, secret)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Replace with proper binary serialization (pgp).")
|
||||
@Serializable
|
||||
data class ByteArrayList(
|
||||
val keys: List<ByteArray>
|
||||
)
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.key.domain.canUnlock
|
||||
import me.proton.core.key.domain.entity.key.PrivateKey
|
||||
import me.proton.core.key.domain.fingerprint
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetRecoveryInactivePrivateKeys @Inject constructor(
|
||||
private val userManager: UserManager,
|
||||
private val cryptoContext: CryptoContext
|
||||
) {
|
||||
suspend operator fun invoke(
|
||||
userId: UserId,
|
||||
keys: List<PrivateKey>,
|
||||
): List<PrivateKey> {
|
||||
val user = userManager.getUser(userId)
|
||||
val inactive = user.keys.filter { it.active?.not() ?: false }
|
||||
val fingerprint = inactive.associateBy { it.privateKey.fingerprint(cryptoContext) }
|
||||
val recoverable = keys.filter { it.fingerprint(cryptoContext) in fingerprint }
|
||||
return recoverable.filter { it.canUnlock(cryptoContext) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.pgp.EncryptedMessage
|
||||
import me.proton.core.crypto.common.pgp.Unarmored
|
||||
import me.proton.core.crypto.common.pgp.UnlockedKey
|
||||
import me.proton.core.crypto.common.pgp.decryptDataWithPasswordOrNull
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.key.domain.entity.key.PrivateKey
|
||||
import me.proton.core.key.domain.entity.key.UnlockedPrivateKey
|
||||
import me.proton.core.key.domain.lock
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.repository.PassphraseRepository
|
||||
import me.proton.core.util.kotlin.deserialize
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetRecoveryPrivateKeys @Inject constructor(
|
||||
private val userManager: UserManager,
|
||||
private val passphraseRepository: PassphraseRepository,
|
||||
private val cryptoContext: CryptoContext
|
||||
) {
|
||||
private val pgpCrypto = cryptoContext.pgpCrypto
|
||||
|
||||
suspend operator fun invoke(
|
||||
userId: UserId,
|
||||
message: EncryptedMessage,
|
||||
): List<PrivateKey> {
|
||||
val user = userManager.getUser(userId, refresh = true)
|
||||
val secrets = user.keys.mapNotNull { key -> key.recoverySecret }
|
||||
secrets.forEach { secret ->
|
||||
val decodedSecret = pgpCrypto.getBase64Decoded(secret)
|
||||
pgpCrypto.decryptDataWithPasswordOrNull(message, decodedSecret)?.let {
|
||||
val byteArrayList = it.decodeToString().deserialize<ByteArrayList>()
|
||||
val passphrase = checkNotNull(passphraseRepository.getPassphrase(userId))
|
||||
return byteArrayList.keys.map { key ->
|
||||
UnlockedPrivateKey(TempUnlockedKey(key), isPrimary = false).use { unlocked ->
|
||||
unlocked.lock(cryptoContext, passphrase = passphrase, isPrimary = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// Only used to create PrivateKey from UnlockedPrivateKey.
|
||||
private class TempUnlockedKey(override val value: Unarmored) : UnlockedKey {
|
||||
override fun close() {
|
||||
value.fill(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.domain.usecase
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.pgp.Based64Encoded
|
||||
|
@ -24,7 +24,7 @@ import me.proton.core.crypto.common.pgp.EncryptedSignature
|
|||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.key.domain.generateNewToken
|
||||
import me.proton.core.key.domain.getBase64Encoded
|
||||
import me.proton.core.key.domain.signData
|
||||
import me.proton.core.key.domain.signText
|
||||
import me.proton.core.key.domain.useKeys
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import javax.inject.Inject
|
||||
|
@ -32,7 +32,7 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Generate and sign a new user primary recovery secret.
|
||||
*/
|
||||
class GenerateRecoverySecret @Inject constructor(
|
||||
class GetRecoverySecret @Inject constructor(
|
||||
private val userManager: UserManager,
|
||||
private val cryptoContext: CryptoContext
|
||||
) {
|
||||
|
@ -42,7 +42,7 @@ class GenerateRecoverySecret @Inject constructor(
|
|||
return userManager.getUser(userId).useKeys(cryptoContext) {
|
||||
val token = generateNewToken(32)
|
||||
val secret = getBase64Encoded(token)
|
||||
val signature = signData(token)
|
||||
val signature = signText(secret)
|
||||
secret to signature
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.domain.usecase
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.eventmanager.domain.EventManagerConfig
|
||||
|
@ -30,14 +30,14 @@ import javax.inject.Inject
|
|||
*/
|
||||
class SetRecoverySecretRemote @Inject constructor(
|
||||
private val eventManagerProvider: EventManagerProvider,
|
||||
private val generateRecoverySecret: GenerateRecoverySecret,
|
||||
private val getRecoverySecret: GetRecoverySecret,
|
||||
private val userSettingsRemoteDataSource: UserSettingsRemoteDataSource
|
||||
) {
|
||||
suspend operator fun invoke(
|
||||
userId: UserId
|
||||
) {
|
||||
eventManagerProvider.suspend(EventManagerConfig.Core(userId)) {
|
||||
val (secret, signature) = generateRecoverySecret(userId)
|
||||
val (secret, signature) = getRecoverySecret(userId)
|
||||
userSettingsRemoteDataSource.setRecoverySecret(userId, secret, signature)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.worker
|
||||
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
||||
interface UserRecoveryWorkerManager {
|
||||
/**
|
||||
* Set the user primary key recovery secret, remotely, in background.
|
||||
*
|
||||
* Note: Once remotely set, local will be updated asap.
|
||||
*/
|
||||
suspend fun enqueueSetRecoverySecret(userId: UserId)
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkConstructor
|
||||
import io.mockk.mockkStatic
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.pgp.PGPCrypto
|
||||
import me.proton.core.crypto.common.pgp.exception.CryptoException
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.key.domain.canUnlock
|
||||
import me.proton.core.key.domain.entity.key.PrivateKey
|
||||
import me.proton.core.key.domain.entity.key.UnlockedPrivateKey
|
||||
import me.proton.core.key.domain.fingerprint
|
||||
import me.proton.core.key.domain.lock
|
||||
import me.proton.core.key.domain.unlockOrNull
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.entity.User
|
||||
import me.proton.core.user.domain.entity.UserKey
|
||||
import me.proton.core.user.domain.repository.PassphraseRepository
|
||||
import org.junit.Before
|
||||
|
||||
/**
|
||||
* Test data: 1 User -> 2 UserKey -> 1 primary/active and 1 inactive.
|
||||
*/
|
||||
abstract class BaseUserKeysTest {
|
||||
|
||||
internal val testSecretValid = "valid"
|
||||
internal val testSecretInvalid = "invalid"
|
||||
|
||||
internal val unlockedKey = mockk<UnlockedPrivateKey> {
|
||||
every { this@mockk.unlockedKey } returns mockk { every { value } returns "unlocked".toByteArray() }
|
||||
}
|
||||
|
||||
internal val testPrivateKeyInactive = mockk<PrivateKey> {
|
||||
every { this@mockk.isActive } returns false
|
||||
every { this@mockk.isPrimary } returns false
|
||||
every { this@mockk.key } returns "inactive.key"
|
||||
}
|
||||
internal val testPrivateKeyPrimary = mockk<PrivateKey> {
|
||||
every { this@mockk.isActive } returns true
|
||||
every { this@mockk.isPrimary } returns true
|
||||
every { this@mockk.key } returns "active.key"
|
||||
}
|
||||
internal val testKey1 = mockk<UserKey> {
|
||||
every { this@mockk.privateKey } returns testPrivateKeyPrimary
|
||||
every { this@mockk.recoverySecret } returns testSecretValid
|
||||
every { this@mockk.active } returns true
|
||||
}
|
||||
internal val testKey2 = mockk<UserKey> {
|
||||
every { this@mockk.privateKey } returns testPrivateKeyInactive
|
||||
every { this@mockk.recoverySecret } returns testSecretInvalid
|
||||
every { this@mockk.active } returns false
|
||||
}
|
||||
internal val testUser = mockk<User> {
|
||||
every { this@mockk.userId } returns UserId("userId")
|
||||
every { this@mockk.keys } returns listOf(testKey1, testKey2)
|
||||
}
|
||||
|
||||
internal val testUserManager = mockk<UserManager> {
|
||||
coEvery { this@mockk.getUser(any(), any()) } returns testUser
|
||||
}
|
||||
|
||||
internal val testDecodedSecret1 = "decodedSecret1".toByteArray()
|
||||
internal val testDecodedSecret2 = "decodedSecret2".toByteArray()
|
||||
internal val testFingerprint1 = "fingerprint1"
|
||||
internal val testFingerprint2 = "fingerprint2"
|
||||
internal val testPgpCrypto = mockk<PGPCrypto>(relaxed = true) {
|
||||
every { this@mockk.getBase64Decoded(testSecretValid) } returns testDecodedSecret1
|
||||
every { this@mockk.getBase64Decoded(testSecretInvalid) } returns testDecodedSecret2
|
||||
every { this@mockk.decryptDataWithPassword(any(), testDecodedSecret1) } returns "{\"keys\":[[0]]}".toByteArray()
|
||||
every { this@mockk.decryptDataWithPassword(any(), testDecodedSecret2) } throws CryptoException()
|
||||
}
|
||||
internal val testCryptoContext = mockk<CryptoContext>(relaxed = true) {
|
||||
every { this@mockk.pgpCrypto } returns testPgpCrypto
|
||||
}
|
||||
internal val encryptedPassphrase = EncryptedByteArray("passphrase".toByteArray())
|
||||
internal val testPassphraseRepository = mockk<PassphraseRepository> {
|
||||
coEvery { this@mockk.getPassphrase(any()) } returns encryptedPassphrase
|
||||
}
|
||||
|
||||
@Before
|
||||
open fun before() {
|
||||
mockkStatic(PrivateKey::unlockOrNull)
|
||||
every { testPrivateKeyPrimary.unlockOrNull(any()) } returns unlockedKey
|
||||
every { testPrivateKeyInactive.unlockOrNull(any()) } returns unlockedKey
|
||||
|
||||
every { testPrivateKeyPrimary.fingerprint(any()) } returns testFingerprint1
|
||||
every { testPrivateKeyInactive.fingerprint(any()) } returns testFingerprint2
|
||||
|
||||
every { testPrivateKeyPrimary.canUnlock(any()) } returns true
|
||||
every { testPrivateKeyInactive.canUnlock(any()) } returns true
|
||||
|
||||
mockkStatic(UnlockedPrivateKey::lock)
|
||||
mockkConstructor(UnlockedPrivateKey::class)
|
||||
every { anyConstructed<UnlockedPrivateKey>().lock(any(), any()) } returns testPrivateKeyInactive
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import me.proton.core.key.domain.unlockOrNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class GetRecoveryFileTest : BaseUserKeysTest() {
|
||||
|
||||
private lateinit var tested: GetRecoveryFile
|
||||
|
||||
@Before
|
||||
override fun before() {
|
||||
super.before()
|
||||
tested = GetRecoveryFile(
|
||||
userManager = testUserManager,
|
||||
cryptoContext = testCryptoContext
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoverFileHappyPath() = runTest {
|
||||
// WHEN
|
||||
tested.invoke(testUser.userId)
|
||||
|
||||
// THEN
|
||||
verify(exactly = 1) { testPrivateKeyPrimary.unlockOrNull(any()) }
|
||||
verify(exactly = 0) { testPrivateKeyInactive.unlockOrNull(any()) }
|
||||
verify(exactly = 1) { testPgpCrypto.getBase64Decoded(testSecretValid) }
|
||||
verify(exactly = 0) { testPgpCrypto.getBase64Decoded(testSecretInvalid) }
|
||||
verify(exactly = 1) { testPgpCrypto.encryptDataWithPassword(any(), testDecodedSecret1) }
|
||||
verify(exactly = 0) { testPgpCrypto.encryptDataWithPassword(any(), testDecodedSecret2) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoverFileThrowIllegalArgumentWhenNoPrimary() = runTest {
|
||||
// GIVEN
|
||||
every { testPrivateKeyPrimary.isPrimary } returns false
|
||||
|
||||
// WHEN
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
tested.invoke(testUser.userId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoverFileThrowIllegalArgumentWhenNoSecret() = runTest {
|
||||
// GIVEN
|
||||
every { testKey1.recoverySecret } returns null
|
||||
every { testKey2.recoverySecret } returns null
|
||||
|
||||
// WHEN
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
tested.invoke(testUser.userId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoverFileThrowIllegalStateWhenNoActive() = runTest {
|
||||
// GIVEN
|
||||
every { testKey1.active } returns false
|
||||
every { testKey2.active } returns false
|
||||
|
||||
// WHEN
|
||||
assertFailsWith<IllegalStateException> {
|
||||
tested.invoke(testUser.userId)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import io.mockk.every
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import me.proton.core.key.domain.canUnlock
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class GetRecoveryInactivePrivateKeysTest : BaseUserKeysTest() {
|
||||
|
||||
private lateinit var tested: GetRecoveryInactivePrivateKeys
|
||||
|
||||
@Before
|
||||
override fun before() {
|
||||
super.before()
|
||||
tested = GetRecoveryInactivePrivateKeys(
|
||||
userManager = testUserManager,
|
||||
cryptoContext = testCryptoContext
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoveryInactivePrivateKeysHappyPath() = runTest {
|
||||
// GIVEN
|
||||
val recoverable = listOf(testPrivateKeyPrimary, testPrivateKeyInactive)
|
||||
|
||||
// WHEN
|
||||
val result = tested.invoke(testUser.userId, recoverable)
|
||||
|
||||
// THEN
|
||||
assertTrue(result.size == 1)
|
||||
assertContains(result, testPrivateKeyInactive)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoveryInactivePrivateKeysCannotUnlock() = runTest {
|
||||
// GIVEN
|
||||
every { testPrivateKeyPrimary.canUnlock(any()) } returns false
|
||||
every { testPrivateKeyInactive.canUnlock(any()) } returns false
|
||||
val recoverable = listOf(testPrivateKeyPrimary, testPrivateKeyInactive)
|
||||
|
||||
// WHEN
|
||||
val result = tested.invoke(testUser.userId, recoverable)
|
||||
|
||||
// THEN
|
||||
assertTrue(result.isEmpty())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.pgp.exception.CryptoException
|
||||
import me.proton.core.user.domain.repository.PassphraseRepository
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class GetRecoveryPrivateKeysTest : BaseUserKeysTest() {
|
||||
|
||||
private lateinit var tested: GetRecoveryPrivateKeys
|
||||
|
||||
@Before
|
||||
override fun before() {
|
||||
super.before()
|
||||
tested = GetRecoveryPrivateKeys(
|
||||
userManager = testUserManager,
|
||||
passphraseRepository = testPassphraseRepository,
|
||||
cryptoContext = testCryptoContext
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoveryPrivateKeysHappyPath() = runTest {
|
||||
// WHEN
|
||||
val result = tested.invoke(testUser.userId, "encryptedMessage")
|
||||
|
||||
// THEN
|
||||
assertTrue(result.size == 1)
|
||||
verify(exactly = 1) { testPgpCrypto.getBase64Decoded(testSecretValid) }
|
||||
verify(exactly = 0) { testPgpCrypto.getBase64Decoded(testSecretInvalid) }
|
||||
|
||||
verify(exactly = 1) { testPgpCrypto.decryptDataWithPassword(any(), testDecodedSecret1) }
|
||||
verify(exactly = 0) { testPgpCrypto.decryptDataWithPassword(any(), testDecodedSecret2) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoveryPrivateKeysRefreshUser() = runTest {
|
||||
// WHEN
|
||||
tested.invoke(testUser.userId, "encryptedMessage")
|
||||
|
||||
// THEN
|
||||
coVerify { testUserManager.getUser(any(), refresh = true) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoveryPrivateKeysReturnsEmptyListWhenDecryptFail() = runTest {
|
||||
// GIVEN
|
||||
every { testPgpCrypto.decryptDataWithPassword(any(), any()) } throws CryptoException()
|
||||
|
||||
// WHEN
|
||||
val result = tested.invoke(testUser.userId, "encryptedMessage")
|
||||
|
||||
// THEN
|
||||
assertTrue(result.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRecoveryPrivateKeysThrowIllegalStateWhenNoPassphrase() = runTest {
|
||||
// GIVEN
|
||||
coEvery { testPassphraseRepository.getPassphrase(any()) } returns null
|
||||
|
||||
// WHEN
|
||||
assertFailsWith<IllegalStateException> {
|
||||
tested.invoke(testUser.userId, "encryptedMessage")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton Technologies AG
|
||||
* Copyright (c) 2024 ProtonTechnologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
|
@ -16,7 +16,7 @@
|
|||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.usersettings.domain.usecase
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
@ -44,7 +44,7 @@ class SetRecoverySecretRemoteTest {
|
|||
lambda<(suspend () -> Unit)>().captured()
|
||||
}
|
||||
}
|
||||
private val generateRecoverySecret: GenerateRecoverySecret = mockk(relaxed = true) {
|
||||
private val getRecoverySecret: GetRecoverySecret = mockk(relaxed = true) {
|
||||
coEvery { this@mockk.invoke(any()) } returns Pair(secret, signature)
|
||||
}
|
||||
private val userSettingsRemoteDataSource: UserSettingsRemoteDataSource = mockk(relaxed = true)
|
||||
|
@ -54,7 +54,7 @@ class SetRecoverySecretRemoteTest {
|
|||
@Before
|
||||
fun setup() {
|
||||
mockkStatic("me.proton.core.eventmanager.domain.extension.EventManagerKt")
|
||||
tested = SetRecoverySecretRemote(eventManagerProvider, generateRecoverySecret, userSettingsRemoteDataSource)
|
||||
tested = SetRecoverySecretRemote(eventManagerProvider, getRecoverySecret, userSettingsRemoteDataSource)
|
||||
}
|
||||
|
||||
@After
|
|
@ -0,0 +1,7 @@
|
|||
public final class me/proton/core/userrecovery/presentation/compose/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
import studio.forface.easygradle.dsl.android.*
|
||||
|
||||
plugins {
|
||||
protonComposeUiLibrary
|
||||
protonDagger
|
||||
}
|
||||
|
||||
protonBuild {
|
||||
apiModeDisabled()
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.userrecovery.presentation.compose"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.presentationCompose),
|
||||
project(Module.userRecoveryDomain),
|
||||
project(Module.userRecoveryPresentation),
|
||||
|
||||
`compose-foundation`,
|
||||
`compose-foundation-layout`,
|
||||
`compose-material`,
|
||||
`compose-runtime`,
|
||||
`compose-ui`,
|
||||
`compose-ui-graphics`,
|
||||
`compose-ui-text`,
|
||||
`coroutines-core`,
|
||||
`hilt-android`,
|
||||
`hilt-navigation-compose`,
|
||||
`lifecycle-common`,
|
||||
`lifecycle-viewModel`,
|
||||
)
|
||||
|
||||
implementation(
|
||||
project(Module.presentation),
|
||||
|
||||
`android-ktx`,
|
||||
`appcompat`,
|
||||
`compose-animation-core`,
|
||||
`compose-material-icons-core`,
|
||||
`compose-material3`,
|
||||
`compose-ui-tooling-preview`,
|
||||
`compose-ui-unit`,
|
||||
`lifecycle-runtime`,
|
||||
)
|
||||
|
||||
debugImplementation(
|
||||
`compose-ui-tooling`,
|
||||
)
|
||||
|
||||
androidTestImplementation(
|
||||
`android-test-runner`,
|
||||
`compose-ui-test`,
|
||||
`compose-ui-test-junit`,
|
||||
`compose-ui-test-manifest`,
|
||||
`junit`,
|
||||
`junit-ktx`,
|
||||
`kotlin-test`
|
||||
)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
public class hilt_aggregated_deps/_me_proton_core_userrecovery_presentation_DeviceRecoveryHandlerInitializer_DeviceRecoveryHandlerInitializerEntryPoint {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/presentation/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/presentation/DeviceRecoveryHandlerInitializer : androidx/startup/Initializer {
|
||||
public static final field $stable I
|
||||
public fun <init> ()V
|
||||
public synthetic fun create (Landroid/content/Context;)Ljava/lang/Object;
|
||||
public fun create (Landroid/content/Context;)V
|
||||
public fun dependencies ()Ljava/util/List;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/userrecovery/presentation/DeviceRecoveryHandlerInitializer$DeviceRecoveryHandlerInitializerEntryPoint {
|
||||
public abstract fun deviceRecoveryHandler ()Lme/proton/core/userrecovery/data/DeviceRecoveryHandler;
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
import studio.forface.easygradle.dsl.android.*
|
||||
|
||||
plugins {
|
||||
protonComposeUiLibrary
|
||||
protonDagger
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
protonBuild {
|
||||
apiModeDisabled()
|
||||
}
|
||||
|
||||
protonCoverage {
|
||||
//branchCoveragePercentage.set(26)
|
||||
//lineCoveragePercentage.set(55)
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.userrecovery.presentation"
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.domain),
|
||||
project(Module.presentation),
|
||||
project(Module.userRecoveryData),
|
||||
project(Module.userRecoveryDomain),
|
||||
activity,
|
||||
`compose-ui`,
|
||||
`constraint-layout`,
|
||||
`coroutines-core`,
|
||||
`hilt-android`,
|
||||
material
|
||||
)
|
||||
|
||||
implementation(
|
||||
// Core
|
||||
project(Module.kotlinUtil),
|
||||
|
||||
// Android
|
||||
`android-ktx`,
|
||||
appcompat,
|
||||
fragment,
|
||||
`lifecycle-common`,
|
||||
`lifecycle-runtime`,
|
||||
`lifecycle-viewModel`,
|
||||
)
|
||||
|
||||
testImplementation(
|
||||
project(Module.androidTest),
|
||||
project(Module.kotlinTest),
|
||||
`android-arch-testing`,
|
||||
`coroutines-test`,
|
||||
junit,
|
||||
`kotlin-test`,
|
||||
mockk,
|
||||
turbine
|
||||
)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2024 Proton AG
|
||||
~ This file is part of Proton AG and ProtonCore.
|
||||
~
|
||||
~ ProtonCore is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ ProtonCore is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application>
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
|
||||
<meta-data
|
||||
android:name="me.proton.core.userrecovery.presentation.DeviceRecoveryHandlerInitializer"
|
||||
android:value="androidx.startup" />
|
||||
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.userrecovery.presentation
|
||||
|
||||
import android.content.Context
|
||||
import androidx.startup.Initializer
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.proton.core.userrecovery.data.DeviceRecoveryHandler
|
||||
|
||||
class DeviceRecoveryHandlerInitializer : Initializer<Unit> {
|
||||
|
||||
override fun create(context: Context) = EntryPointAccessors.fromApplication(
|
||||
context.applicationContext,
|
||||
DeviceRecoveryHandlerInitializerEntryPoint::class.java
|
||||
).deviceRecoveryHandler().start()
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>?>> = emptyList()
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface DeviceRecoveryHandlerInitializerEntryPoint {
|
||||
fun deviceRecoveryHandler(): DeviceRecoveryHandler
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
public final class me/proton/core/userrecovery/test/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Proton AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonCore is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.android.retrofit
|
||||
import studio.forface.easygradle.dsl.api
|
||||
import studio.forface.easygradle.dsl.`coroutines-core`
|
||||
import studio.forface.easygradle.dsl.implementation
|
||||
import studio.forface.easygradle.dsl.`kotlin-test`
|
||||
import studio.forface.easygradle.dsl.`kotlin-test-junit`
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
}
|
||||
|
||||
protonCoverage.disabled.set(true)
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.userrecovery.test"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.quark),
|
||||
junit
|
||||
)
|
||||
|
||||
implementation(
|
||||
project(Module.androidInstrumentedTest),
|
||||
`androidx-test-monitor`,
|
||||
`compose-ui-test-junit`,
|
||||
`coroutines-core`,
|
||||
fusion,
|
||||
`kotlin-test`,
|
||||
`kotlin-test-junit`,
|
||||
retrofit,
|
||||
uiautomator
|
||||
)
|
||||
}
|
|
@ -2,10 +2,6 @@ public class hilt_aggregated_deps/_me_proton_core_usersettings_data_worker_Fetch
|
|||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public class hilt_aggregated_deps/_me_proton_core_usersettings_data_worker_SetRecoverySecretWorker_HiltModule {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public class hilt_aggregated_deps/_me_proton_core_usersettings_data_worker_UpdateUserSettingsWorker_HiltModule {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
@ -17,26 +13,6 @@ public final class me/proton/core/usersettings/data/BuildConfig {
|
|||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl : me/proton/core/usersettings/domain/IsDeviceRecoveryEnabled {
|
||||
public static final field Companion Lme/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl$Companion;
|
||||
public fun <init> (Landroid/content/Context;Lme/proton/core/featureflag/domain/FeatureFlagManager;)V
|
||||
public fun invoke (Lme/proton/core/domain/entity/UserId;)Z
|
||||
public fun isLocalEnabled ()Z
|
||||
public fun isRemoteEnabled (Lme/proton/core/domain/entity/UserId;)Z
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl$Companion {
|
||||
public final fun getFeatureId ()Lme/proton/core/featureflag/domain/entity/FeatureId;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl_Factory : dagger/internal/Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;)Lme/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl_Factory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl;
|
||||
public static fun newInstance (Landroid/content/Context;Lme/proton/core/featureflag/domain/FeatureFlagManager;)Lme/proton/core/usersettings/data/IsDeviceRecoveryEnabledImpl;
|
||||
}
|
||||
|
||||
public class me/proton/core/usersettings/data/UserSettingsEventListener : me/proton/core/eventmanager/domain/EventListener {
|
||||
public fun <init> (Lme/proton/core/usersettings/data/db/UserSettingsDatabase;Lme/proton/core/usersettings/domain/repository/UserSettingsRepository;)V
|
||||
public fun deserializeEvents (Lme/proton/core/eventmanager/domain/EventManagerConfig;Lme/proton/core/eventmanager/domain/entity/EventsResponse;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
@ -973,7 +949,6 @@ public final class me/proton/core/usersettings/data/repository/UserSettingsRepos
|
|||
public fun getUserSettings (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun getUserSettingsFlow (Lme/proton/core/domain/entity/UserId;Z)Lkotlinx/coroutines/flow/Flow;
|
||||
public fun markAsStale (Lme/proton/core/domain/entity/UserId;)V
|
||||
public fun setRecoverySecret (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun setUsername (Lme/proton/core/domain/entity/UserId;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun updateCrashReports (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun updateLoginPassword (Lme/proton/core/domain/entity/UserId;Lme/proton/core/crypto/common/srp/SrpProofs;Ljava/lang/String;Ljava/lang/String;Lme/proton/core/crypto/common/srp/Auth;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
@ -1021,37 +996,6 @@ public abstract interface class me/proton/core/usersettings/data/worker/FetchUse
|
|||
public abstract fun bind (Lme/proton/core/usersettings/data/worker/FetchUserSettingsWorker_AssistedFactory;)Landroidx/hilt/work/WorkerAssistedFactory;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/worker/SetRecoverySecretWorker : androidx/work/CoroutineWorker {
|
||||
public static final field Companion Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker$Companion;
|
||||
public fun <init> (Landroid/content/Context;Landroidx/work/WorkerParameters;Lme/proton/core/usersettings/domain/usecase/SetRecoverySecretRemote;)V
|
||||
public fun doWork (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public final fun getContext ()Landroid/content/Context;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/worker/SetRecoverySecretWorker$Companion {
|
||||
public final fun getRequest (Lme/proton/core/domain/entity/UserId;)Landroidx/work/OneTimeWorkRequest;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/usersettings/data/worker/SetRecoverySecretWorker_AssistedFactory : androidx/hilt/work/WorkerAssistedFactory {
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/worker/SetRecoverySecretWorker_AssistedFactory_Impl : me/proton/core/usersettings/data/worker/SetRecoverySecretWorker_AssistedFactory {
|
||||
public synthetic fun create (Landroid/content/Context;Landroidx/work/WorkerParameters;)Landroidx/work/ListenableWorker;
|
||||
public fun create (Landroid/content/Context;Landroidx/work/WorkerParameters;)Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker;
|
||||
public static fun create (Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker_Factory;)Ljavax/inject/Provider;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/worker/SetRecoverySecretWorker_Factory {
|
||||
public fun <init> (Ljavax/inject/Provider;)V
|
||||
public static fun create (Ljavax/inject/Provider;)Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker_Factory;
|
||||
public fun get (Landroid/content/Context;Landroidx/work/WorkerParameters;)Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker;
|
||||
public static fun newInstance (Landroid/content/Context;Landroidx/work/WorkerParameters;Lme/proton/core/usersettings/domain/usecase/SetRecoverySecretRemote;)Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/usersettings/data/worker/SetRecoverySecretWorker_HiltModule {
|
||||
public abstract fun bind (Lme/proton/core/usersettings/data/worker/SetRecoverySecretWorker_AssistedFactory;)Landroidx/hilt/work/WorkerAssistedFactory;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/data/worker/UpdateUserSettingsWorker : androidx/work/CoroutineWorker {
|
||||
public static final field Companion Lme/proton/core/usersettings/data/worker/UpdateUserSettingsWorker$Companion;
|
||||
public fun <init> (Landroid/content/Context;Landroidx/work/WorkerParameters;Lme/proton/core/usersettings/domain/usecase/UpdateUserSettingsRemote;Lme/proton/core/usersettings/domain/repository/UserSettingsRepository;)V
|
||||
|
|
|
@ -29,7 +29,7 @@ protonBuild {
|
|||
}
|
||||
|
||||
protonCoverage {
|
||||
branchCoveragePercentage.set(62)
|
||||
branchCoveragePercentage.set(59)
|
||||
lineCoveragePercentage.set(81)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import me.proton.core.domain.entity.SessionUserId
|
|||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.usersettings.data.extension.toUserSettingsPropertySerializable
|
||||
import me.proton.core.usersettings.data.worker.FetchUserSettingsWorker
|
||||
import me.proton.core.usersettings.data.worker.SetRecoverySecretWorker
|
||||
import me.proton.core.usersettings.data.worker.UpdateUserSettingsWorker
|
||||
import me.proton.core.usersettings.domain.entity.UserSettings
|
||||
import me.proton.core.usersettings.domain.entity.UserSettingsProperty
|
||||
|
@ -71,14 +70,6 @@ class UserSettingsRepositoryImpl @Inject constructor(
|
|||
override suspend fun setUsername(sessionUserId: SessionUserId, username: String): Boolean =
|
||||
remoteDataSource.setUsername(sessionUserId, username)
|
||||
|
||||
override suspend fun setRecoverySecret(userId: UserId) {
|
||||
workManager.enqueueUniqueWork(
|
||||
"setRecoverySecretWork-${userId.id}",
|
||||
ExistingWorkPolicy.KEEP,
|
||||
SetRecoverySecretWorker.getRequest(userId)
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun updateUserSettings(userSettings: UserSettings) {
|
||||
localDataSource.insertOrUpdate(userSettings)
|
||||
}
|
||||
|
|
|
@ -399,20 +399,6 @@ class UserSettingsRepositoryImplTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setRecoverySecret() = runTest(dispatcherProvider.Main) {
|
||||
// WHEN
|
||||
repository.setRecoverySecret(UserId(testUserId))
|
||||
// THEN
|
||||
verify {
|
||||
workManager.enqueueUniqueWork(
|
||||
"setRecoverySecretWork-test-user-id",
|
||||
ExistingWorkPolicy.KEEP,
|
||||
any<OneTimeWorkRequest>()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun localObjectIsReturnedForCredentialLess() = runTest(dispatcherProvider.Main) {
|
||||
// GIVEN
|
||||
|
|
|
@ -6,12 +6,6 @@ public final class me/proton/core/usersettings/domain/DeviceSettingsHandlerKt {
|
|||
public static final fun onDeviceSettingsChanged (Lme/proton/core/usersettings/domain/DeviceSettingsHandler;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/usersettings/domain/IsDeviceRecoveryEnabled {
|
||||
public abstract fun invoke (Lme/proton/core/domain/entity/UserId;)Z
|
||||
public abstract fun isLocalEnabled ()Z
|
||||
public abstract fun isRemoteEnabled (Lme/proton/core/domain/entity/UserId;)Z
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/domain/LogTag {
|
||||
public static final field DEFAULT Ljava/lang/String;
|
||||
public static final field INSTANCE Lme/proton/core/usersettings/domain/LogTag;
|
||||
|
@ -348,7 +342,6 @@ public abstract interface class me/proton/core/usersettings/domain/repository/Us
|
|||
public abstract fun getUserSettings (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun getUserSettingsFlow (Lme/proton/core/domain/entity/UserId;Z)Lkotlinx/coroutines/flow/Flow;
|
||||
public abstract fun markAsStale (Lme/proton/core/domain/entity/UserId;)V
|
||||
public abstract fun setRecoverySecret (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun setUsername (Lme/proton/core/domain/entity/UserId;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun updateCrashReports (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun updateLoginPassword (Lme/proton/core/domain/entity/UserId;Lme/proton/core/crypto/common/srp/SrpProofs;Ljava/lang/String;Ljava/lang/String;Lme/proton/core/crypto/common/srp/Auth;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
@ -362,11 +355,6 @@ public final class me/proton/core/usersettings/domain/repository/UserSettingsRep
|
|||
public static synthetic fun getUserSettingsFlow$default (Lme/proton/core/usersettings/domain/repository/UserSettingsRepository;Lme/proton/core/domain/entity/UserId;ZILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/domain/usecase/GenerateRecoverySecret {
|
||||
public fun <init> (Lme/proton/core/user/domain/UserManager;Lme/proton/core/crypto/common/context/CryptoContext;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/domain/usecase/GetOrganization {
|
||||
public fun <init> (Lme/proton/core/usersettings/domain/repository/OrganizationRepository;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
@ -421,11 +409,6 @@ public final class me/proton/core/usersettings/domain/usecase/PerformUpdateUserP
|
|||
public static synthetic fun invoke$default (Lme/proton/core/usersettings/domain/usecase/PerformUpdateUserPassword;ZLme/proton/core/domain/entity/UserId;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/domain/usecase/SetRecoverySecretRemote {
|
||||
public fun <init> (Lme/proton/core/eventmanager/domain/EventManagerProvider;Lme/proton/core/usersettings/domain/usecase/GenerateRecoverySecret;Lme/proton/core/usersettings/domain/repository/UserSettingsRemoteDataSource;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/proton/core/usersettings/domain/usecase/SetupUsername {
|
||||
public fun <init> (Lme/proton/core/user/domain/repository/UserRepository;Lme/proton/core/usersettings/domain/repository/UserSettingsRepository;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
|
|
@ -20,6 +20,7 @@ import studio.forface.easygradle.dsl.*
|
|||
|
||||
plugins {
|
||||
protonKotlinLibrary
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
protonBuild {
|
||||
|
@ -27,8 +28,8 @@ protonBuild {
|
|||
}
|
||||
|
||||
protonCoverage {
|
||||
branchCoveragePercentage.set(38)
|
||||
lineCoveragePercentage.set(71)
|
||||
branchCoveragePercentage.set(39)
|
||||
lineCoveragePercentage.set(72)
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
@ -47,6 +48,7 @@ dependencies {
|
|||
|
||||
implementation(
|
||||
project(Module.kotlinUtil),
|
||||
`serialization-json`
|
||||
)
|
||||
|
||||
testImplementation(
|
||||
|
|
|
@ -30,13 +30,6 @@ interface UserSettingsRepository {
|
|||
|
||||
suspend fun setUsername(sessionUserId: SessionUserId, username: String): Boolean
|
||||
|
||||
/**
|
||||
* Set the user primary key recovery secret, remotely, in background.
|
||||
*
|
||||
* Note: Once remotely set, local will be updated asap.
|
||||
*/
|
||||
suspend fun setRecoverySecret(userId: UserId)
|
||||
|
||||
/**
|
||||
* Update [UserSettings], locally.
|
||||
*
|
||||
|
|
|
@ -51,6 +51,7 @@ dependencies {
|
|||
project(Module.domain),
|
||||
project(Module.presentation),
|
||||
project(Module.presentationCompose),
|
||||
project(Module.userSettingsData),
|
||||
project(Module.userSettingsDomain),
|
||||
project(Module.accountManagerPresentation),
|
||||
project(Module.accountRecoveryDomain),
|
||||
|
|
Loading…
Reference in New Issue