mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
Create policy manager (#899)
This commit is contained in:
parent
794b68d364
commit
d538e37606
21 changed files with 488 additions and 173 deletions
|
@ -86,11 +86,6 @@ interface AuthRepository : AuthenticatorProvider {
|
|||
*/
|
||||
val passwordPolicies: List<PolicyInformation.MasterPassword>
|
||||
|
||||
/**
|
||||
* Return whether there are any export vault policies enabled for the current user.
|
||||
*/
|
||||
val hasExportVaultPoliciesEnabled: Boolean
|
||||
|
||||
/**
|
||||
* The reason for resetting the password.
|
||||
*/
|
||||
|
|
|
@ -56,7 +56,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.SsoCallbackResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.currentUserPoliciesListFlow
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.policyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.toUserState
|
||||
|
@ -65,8 +64,10 @@ import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsList
|
|||
import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsListFlow
|
||||
import com.x8bit.bitwarden.data.auth.util.KdfParamsConstants.DEFAULT_PBKDF2_ITERATIONS
|
||||
import com.x8bit.bitwarden.data.auth.util.toSdkParams
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.util.getActivePolicies
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
|
@ -123,6 +124,7 @@ class AuthRepositoryImpl(
|
|||
private val vaultRepository: VaultRepository,
|
||||
private val userLogoutManager: UserLogoutManager,
|
||||
private val pushManager: PushManager,
|
||||
private val policyManager: PolicyManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
private val elapsedRealtimeMillisProvider: () -> Long = { SystemClock.elapsedRealtime() },
|
||||
) : AuthRepository {
|
||||
|
@ -235,21 +237,7 @@ class AuthRepositoryImpl(
|
|||
by mutableHasPendingAccountAdditionStateFlow::value
|
||||
|
||||
override val passwordPolicies: List<PolicyInformation.MasterPassword>
|
||||
get() = activeUserId?.let { userId ->
|
||||
authDiskSource
|
||||
.getPolicies(userId)
|
||||
?.filter { it.type == PolicyTypeJson.MASTER_PASSWORD && it.isEnabled }
|
||||
?.mapNotNull { it.policyInformation as? PolicyInformation.MasterPassword }
|
||||
.orEmpty()
|
||||
} ?: emptyList()
|
||||
|
||||
override val hasExportVaultPoliciesEnabled: Boolean
|
||||
get() = activeUserId?.let { userId ->
|
||||
authDiskSource
|
||||
.getPolicies(userId)
|
||||
?.any { it.type == PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT && it.isEnabled }
|
||||
?: false
|
||||
} ?: false
|
||||
get() = policyManager.getActivePolicies()
|
||||
|
||||
override val passwordResetReason: ForcePasswordResetReason?
|
||||
get() = authDiskSource
|
||||
|
@ -274,7 +262,8 @@ class AuthRepositoryImpl(
|
|||
.launchIn(unconfinedScope)
|
||||
|
||||
// When the policies for the user have been set, complete the login process.
|
||||
authDiskSource.currentUserPoliciesListFlow
|
||||
policyManager
|
||||
.getActivePoliciesFlow(type = PolicyTypeJson.MASTER_PASSWORD)
|
||||
.onEach { policies ->
|
||||
val userId = activeUserId ?: return@onEach
|
||||
|
||||
|
@ -1148,7 +1137,6 @@ class AuthRepositoryImpl(
|
|||
// If there are no master password policies that are enabled and should be
|
||||
// enforced on login, the check should complete.
|
||||
val passwordPolicies = policyList
|
||||
.filter { it.type == PolicyTypeJson.MASTER_PASSWORD && it.isEnabled }
|
||||
.mapNotNull { it.policyInformation as? PolicyInformation.MasterPassword }
|
||||
.filter { it.enforceOnLogin == true }
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
|
|||
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepositoryImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
|
@ -53,6 +54,7 @@ object AuthRepositoryModule {
|
|||
vaultRepository: VaultRepository,
|
||||
userLogoutManager: UserLogoutManager,
|
||||
pushManager: PushManager,
|
||||
policyManager: PolicyManager,
|
||||
): AuthRepository = AuthRepositoryImpl(
|
||||
clock = clock,
|
||||
accountsService = accountsService,
|
||||
|
@ -71,5 +73,6 @@ object AuthRepositoryModule {
|
|||
vaultRepository = vaultRepository,
|
||||
userLogoutManager = userLogoutManager,
|
||||
pushManager = pushManager,
|
||||
policyManager = policyManager,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,12 +2,10 @@ package com.x8bit.bitwarden.data.auth.repository.util
|
|||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
|
@ -55,22 +53,3 @@ val AuthDiskSource.userOrganizationsListFlow: Flow<List<UserOrganizations>>
|
|||
) { values -> values.toList() }
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
/**
|
||||
* Returns a [Flow] that emits distinct updates to the
|
||||
* current user's [SyncResponseJson.Policy] list.
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val AuthDiskSource.currentUserPoliciesListFlow: Flow<List<SyncResponseJson.Policy>?>
|
||||
get() =
|
||||
this
|
||||
.userStateFlow
|
||||
.flatMapLatest { userStateJson ->
|
||||
userStateJson
|
||||
?.activeUserId
|
||||
?.let { activeUserId ->
|
||||
this.getPoliciesFlow(activeUserId)
|
||||
}
|
||||
?: emptyFlow()
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* A manager for pulling policies from the local data store and filtering them as needed.
|
||||
*/
|
||||
interface PolicyManager {
|
||||
/**
|
||||
* Returns a flow of all the active policies of the given type.
|
||||
*/
|
||||
fun getActivePoliciesFlow(type: PolicyTypeJson): Flow<List<SyncResponseJson.Policy>>
|
||||
|
||||
/**
|
||||
* Get all the policies of the given [type] that are enabled and applicable to the user.
|
||||
*/
|
||||
fun getActivePolicies(type: PolicyTypeJson): List<SyncResponseJson.Policy>
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationStatusType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* The default [PolicyManager] implementation. This class is responsible for
|
||||
* loading policies for the current user and filtering them as needed.
|
||||
*/
|
||||
class PolicyManagerImpl(
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
) : PolicyManager {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun getActivePoliciesFlow(type: PolicyTypeJson): Flow<List<SyncResponseJson.Policy>> =
|
||||
authDiskSource
|
||||
.userStateFlow
|
||||
.flatMapLatest { userStateJson ->
|
||||
userStateJson
|
||||
?.activeUserId
|
||||
?.let { activeUserId ->
|
||||
authDiskSource.getPoliciesFlow(activeUserId)
|
||||
.map {
|
||||
filterPolicies(
|
||||
userId = activeUserId,
|
||||
type = type,
|
||||
policies = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
?: emptyFlow()
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
override fun getActivePolicies(type: PolicyTypeJson): List<SyncResponseJson.Policy> =
|
||||
authDiskSource
|
||||
.userState
|
||||
?.activeUserId
|
||||
?.let { userId ->
|
||||
filterPolicies(
|
||||
userId = userId,
|
||||
type = type,
|
||||
policies = authDiskSource.getPolicies(userId = userId),
|
||||
)
|
||||
}
|
||||
?: emptyList()
|
||||
|
||||
/**
|
||||
* A helper method to filter policies.
|
||||
*/
|
||||
private fun filterPolicies(
|
||||
userId: String,
|
||||
type: PolicyTypeJson,
|
||||
policies: List<SyncResponseJson.Policy>?,
|
||||
): List<SyncResponseJson.Policy> {
|
||||
if (policies.isNullOrEmpty()) return emptyList()
|
||||
|
||||
// Get a list of the user's organizations that enforce policies.
|
||||
val organizationIdsWithActivePolicies = authDiskSource
|
||||
.getOrganizations(userId)
|
||||
?.filter {
|
||||
it.shouldUsePolicies &&
|
||||
it.isEnabled &&
|
||||
it.status >= OrganizationStatusType.ACCEPTED &&
|
||||
!isOrganizationExemptFromPolicies(it, type)
|
||||
}
|
||||
?.map { it.id }
|
||||
.orEmpty()
|
||||
|
||||
// Filter the policies based on the type, whether the policy is active,
|
||||
// and whether the organization rules except the user from the policy.
|
||||
return policies.filter {
|
||||
it.type == type &&
|
||||
it.isEnabled &&
|
||||
organizationIdsWithActivePolicies.contains(it.organizationId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to determine if the organization is exempt from policies.
|
||||
*/
|
||||
private fun isOrganizationExemptFromPolicies(
|
||||
organization: SyncResponseJson.Profile.Organization,
|
||||
policyType: PolicyTypeJson,
|
||||
): Boolean =
|
||||
if (policyType == PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT) {
|
||||
organization.type == OrganizationType.OWNER
|
||||
} else {
|
||||
(organization.type == OrganizationType.OWNER ||
|
||||
organization.type == OrganizationType.ADMIN) ||
|
||||
organization.permissions.shouldManagePolicies
|
||||
}
|
||||
}
|
|
@ -20,6 +20,8 @@ import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManager
|
|||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConnectionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConnectionManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.SdkClientManager
|
||||
|
@ -124,6 +126,14 @@ object PlatformManagerModule {
|
|||
context = application.applicationContext,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePolicyManager(
|
||||
authDiskSource: AuthDiskSource,
|
||||
): PolicyManager = PolicyManagerImpl(
|
||||
authDiskSource = authDiskSource,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePushManager(
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.util
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.policyInformation
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
|
||||
/**
|
||||
* Get a list of active policies with the data decoded to the specified type.
|
||||
*/
|
||||
inline fun <reified T : PolicyInformation> PolicyManager.getActivePolicies(): List<T> {
|
||||
val type = when (T::class.java) {
|
||||
PolicyInformation.MasterPassword::class.java -> PolicyTypeJson.MASTER_PASSWORD
|
||||
PolicyInformation.PasswordGenerator::class.java -> PolicyTypeJson.PASSWORD_GENERATOR
|
||||
|
||||
else -> {
|
||||
throw IllegalStateException(
|
||||
"Looks like you are missing a branch in your when statement. Update " +
|
||||
"getActivePolicies() to handle all PolicyInformation implementations.",
|
||||
)
|
||||
}
|
||||
}
|
||||
return this
|
||||
.getActivePolicies(type = type)
|
||||
.mapNotNull { it.policyInformation as? T }
|
||||
}
|
|
@ -8,8 +8,9 @@ import com.bitwarden.generators.PasswordGeneratorRequest
|
|||
import com.bitwarden.generators.UsernameGeneratorRequest
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.policyInformation
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.util.getActivePolicies
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.observeWhenSubscribedAndLoggedIn
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
|
||||
|
@ -26,7 +27,6 @@ import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedRandom
|
|||
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratorResult
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.model.UsernameGenerationOptions
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
|
@ -48,12 +48,14 @@ import kotlin.math.max
|
|||
* Default implementation of [GeneratorRepository].
|
||||
*/
|
||||
@Singleton
|
||||
@Suppress("LongParameterList")
|
||||
class GeneratorRepositoryImpl(
|
||||
private val generatorSdkSource: GeneratorSdkSource,
|
||||
private val generatorDiskSource: GeneratorDiskSource,
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
private val vaultSdkSource: VaultSdkSource,
|
||||
private val passwordHistoryDiskSource: PasswordHistoryDiskSource,
|
||||
private val policyManager: PolicyManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
) : GeneratorRepository {
|
||||
|
||||
|
@ -201,10 +203,9 @@ class GeneratorRepositoryImpl(
|
|||
},
|
||||
)
|
||||
|
||||
@Suppress("LongMethod", "ReturnCount", "CyclomaticComplexMethod")
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
override fun getPasswordGeneratorPolicy(): PolicyInformation.PasswordGenerator? {
|
||||
val userId = authDiskSource.userState?.activeUserId ?: return null
|
||||
val policies = authDiskSource.getPolicies(userId) ?: return null
|
||||
val policies: List<PolicyInformation.PasswordGenerator> = policyManager.getActivePolicies()
|
||||
|
||||
var minLength: Int? = null
|
||||
var useUpper = false
|
||||
|
@ -218,8 +219,7 @@ class GeneratorRepositoryImpl(
|
|||
var includeNumber = false
|
||||
|
||||
var isPassphrasePresent = false
|
||||
policies.filter { it.type == PolicyTypeJson.PASSWORD_GENERATOR && it.isEnabled }
|
||||
.mapNotNull { it.policyInformation as? PolicyInformation.PasswordGenerator }
|
||||
policies
|
||||
.forEach { policy ->
|
||||
if (policy.defaultType == PolicyInformation.PasswordGenerator.TYPE_PASSPHRASE) {
|
||||
isPassphrasePresent = true
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.data.tools.generator.repository.di
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.PasswordHistoryDiskSource
|
||||
|
@ -30,6 +31,7 @@ object GeneratorRepositoryModule {
|
|||
vaultSdkSource: VaultSdkSource,
|
||||
passwordHistoryDiskSource: PasswordHistoryDiskSource,
|
||||
dispatcherManager: DispatcherManager,
|
||||
policyManager: PolicyManager,
|
||||
): GeneratorRepository = GeneratorRepositoryImpl(
|
||||
generatorSdkSource = generatorSdkSource,
|
||||
generatorDiskSource = generatorDiskSource,
|
||||
|
@ -37,5 +39,6 @@ object GeneratorRepositoryModule {
|
|||
vaultSdkSource = vaultSdkSource,
|
||||
passwordHistoryDiskSource = passwordHistoryDiskSource,
|
||||
dispatcherManager = dispatcherManager,
|
||||
policyManager = policyManager,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.serializer.BaseEnumeratedIntSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a user's status in an organization.
|
||||
*/
|
||||
@Serializable(OrganizationStatusTypeSerializer::class)
|
||||
enum class OrganizationStatusType {
|
||||
/**
|
||||
* The user has been invited to the organization.
|
||||
*/
|
||||
@SerialName("0")
|
||||
INVITED,
|
||||
|
||||
/**
|
||||
* The user has accepted the invite to the organization.
|
||||
*/
|
||||
@SerialName("1")
|
||||
ACCEPTED,
|
||||
|
||||
/**
|
||||
* The user has been confirmed in the organization.
|
||||
*/
|
||||
@SerialName("2")
|
||||
CONFIRMED,
|
||||
}
|
||||
|
||||
@Keep
|
||||
private class OrganizationStatusTypeSerializer :
|
||||
BaseEnumeratedIntSerializer<OrganizationStatusType>(
|
||||
OrganizationStatusType.entries.toTypedArray(),
|
||||
)
|
|
@ -0,0 +1,47 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.serializer.BaseEnumeratedIntSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a user's role in an organization.
|
||||
*/
|
||||
@Serializable(OrganizationTypeSerializer::class)
|
||||
enum class OrganizationType {
|
||||
/**
|
||||
* The user is an owner of the organization.
|
||||
*/
|
||||
@SerialName("0")
|
||||
OWNER,
|
||||
|
||||
/**
|
||||
* The user is an admin in the organization.
|
||||
*/
|
||||
@SerialName("1")
|
||||
ADMIN,
|
||||
|
||||
/**
|
||||
* The user is an ordinary user in the organization.
|
||||
*/
|
||||
@SerialName("2")
|
||||
USER,
|
||||
|
||||
/**
|
||||
* The user is a manager in the organization.
|
||||
*/
|
||||
@SerialName("3")
|
||||
MANAGER,
|
||||
|
||||
/**
|
||||
* The user has a custom role in the organization.
|
||||
*/
|
||||
@SerialName("4")
|
||||
CUSTOM,
|
||||
}
|
||||
|
||||
@Keep
|
||||
private class OrganizationTypeSerializer : BaseEnumeratedIntSerializer<OrganizationType>(
|
||||
OrganizationType.entries.toTypedArray(),
|
||||
)
|
|
@ -246,7 +246,7 @@ data class SyncResponseJson(
|
|||
val keyConnectorUrl: String?,
|
||||
|
||||
@SerialName("type")
|
||||
val type: Int,
|
||||
val type: OrganizationType,
|
||||
|
||||
@SerialName("seats")
|
||||
val seats: Int?,
|
||||
|
@ -326,7 +326,7 @@ data class SyncResponseJson(
|
|||
val familySponsorshipValidUntil: ZonedDateTime?,
|
||||
|
||||
@SerialName("status")
|
||||
val status: Int,
|
||||
val status: OrganizationStatusType,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,8 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
|
@ -26,6 +28,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class ExportVaultViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val policyManager: PolicyManager,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<ExportVaultState, ExportVaultEvent, ExportVaultAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
|
@ -33,7 +36,9 @@ class ExportVaultViewModel @Inject constructor(
|
|||
dialogState = null,
|
||||
exportFormat = ExportVaultFormat.JSON,
|
||||
passwordInput = "",
|
||||
policyPreventsExport = authRepository.hasExportVaultPoliciesEnabled,
|
||||
policyPreventsExport = policyManager
|
||||
.getActivePolicies(type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT)
|
||||
.any(),
|
||||
),
|
||||
) {
|
||||
init {
|
||||
|
|
|
@ -70,6 +70,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.toUserState
|
|||
import com.x8bit.bitwarden.data.auth.repository.util.toUserStateJson
|
||||
import com.x8bit.bitwarden.data.auth.util.toSdkParams
|
||||
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
|
@ -79,6 +80,7 @@ import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFl
|
|||
import com.x8bit.bitwarden.data.platform.util.asFailure
|
||||
import com.x8bit.bitwarden.data.platform.util.asSuccess
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
|
@ -194,10 +196,16 @@ class AuthRepositoryTest {
|
|||
|
||||
private val mutableLogoutFlow = bufferedMutableSharedFlow<Unit>()
|
||||
private val mutableSyncOrgKeysFlow = bufferedMutableSharedFlow<Unit>()
|
||||
private val mutableActivePolicyFlow = bufferedMutableSharedFlow<List<SyncResponseJson.Policy>>()
|
||||
private val pushManager: PushManager = mockk {
|
||||
every { logoutFlow } returns mutableLogoutFlow
|
||||
every { syncOrgKeysFlow } returns mutableSyncOrgKeysFlow
|
||||
}
|
||||
private val policyManager: PolicyManager = mockk {
|
||||
every {
|
||||
getActivePoliciesFlow(type = PolicyTypeJson.MASTER_PASSWORD)
|
||||
} returns mutableActivePolicyFlow
|
||||
}
|
||||
|
||||
private var elapsedRealtimeMillis = 123456789L
|
||||
|
||||
|
@ -219,6 +227,7 @@ class AuthRepositoryTest {
|
|||
userLogoutManager = userLogoutManager,
|
||||
dispatcherManager = dispatcherManager,
|
||||
pushManager = pushManager,
|
||||
policyManager = policyManager,
|
||||
elapsedRealtimeMillisProvider = { elapsedRealtimeMillis },
|
||||
)
|
||||
|
||||
|
@ -406,9 +415,8 @@ class AuthRepositoryTest {
|
|||
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
|
||||
|
||||
// Set policies that will fail the password.
|
||||
fakeAuthDiskSource.storePolicies(
|
||||
userId = USER_ID_1,
|
||||
policies = listOf(
|
||||
mutableActivePolicyFlow.emit(
|
||||
listOf(
|
||||
createMockPolicy(
|
||||
type = PolicyTypeJson.MASTER_PASSWORD,
|
||||
isEnabled = true,
|
||||
|
@ -509,38 +517,6 @@ class AuthRepositoryTest {
|
|||
assertNull(repository.rememberedOrgIdentifier)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hasExportVaultPoliciesEnabled checks if any export vault policies are enabled`() {
|
||||
fakeAuthDiskSource.userState = SINGLE_USER_STATE_1
|
||||
|
||||
// No stored policies returns false.
|
||||
assertFalse(repository.hasExportVaultPoliciesEnabled)
|
||||
|
||||
// Stored but disabled policies returns false.
|
||||
fakeAuthDiskSource.storePolicies(
|
||||
userId = USER_ID_1,
|
||||
policies = listOf(
|
||||
createMockPolicy(
|
||||
type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT,
|
||||
isEnabled = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
assertFalse(repository.hasExportVaultPoliciesEnabled)
|
||||
|
||||
// Stored enabled policies returns true.
|
||||
fakeAuthDiskSource.storePolicies(
|
||||
userId = USER_ID_1,
|
||||
policies = listOf(
|
||||
createMockPolicy(
|
||||
type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT,
|
||||
isEnabled = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
assertTrue(repository.hasExportVaultPoliciesEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `passwordResetReason should pull from the user's profile in AuthDiskSource`() = runTest {
|
||||
val updatedProfile = ACCOUNT_1.profile.copy(
|
||||
|
@ -3702,7 +3678,7 @@ class AuthRepositoryTest {
|
|||
fun `validatePasswordAgainstPolicy validates password against policy requirements`() = runTest {
|
||||
fakeAuthDiskSource.userState = SINGLE_USER_STATE_1
|
||||
|
||||
// A helper method to set a policy in the store with the given parameters.
|
||||
// A helper method to set a policy with the given parameters.
|
||||
fun setPolicy(
|
||||
minLength: Int = 0,
|
||||
minComplexity: Int? = null,
|
||||
|
@ -3711,22 +3687,21 @@ class AuthRepositoryTest {
|
|||
requireNumbers: Boolean = false,
|
||||
requireSpecial: Boolean = false,
|
||||
) {
|
||||
fakeAuthDiskSource.storePolicies(
|
||||
userId = USER_ID_1,
|
||||
policies = listOf(
|
||||
createMockPolicy(
|
||||
type = PolicyTypeJson.MASTER_PASSWORD,
|
||||
isEnabled = true,
|
||||
data = buildJsonObject {
|
||||
put(key = "minLength", value = minLength)
|
||||
put(key = "minComplexity", value = minComplexity)
|
||||
put(key = "requireUpper", value = requireUpper)
|
||||
put(key = "requireLower", value = requireLower)
|
||||
put(key = "requireNumbers", value = requireNumbers)
|
||||
put(key = "requireSpecial", value = requireSpecial)
|
||||
put(key = "enforceOnLogin", value = true)
|
||||
},
|
||||
),
|
||||
every {
|
||||
policyManager.getActivePolicies(type = PolicyTypeJson.MASTER_PASSWORD)
|
||||
} returns listOf(
|
||||
createMockPolicy(
|
||||
type = PolicyTypeJson.MASTER_PASSWORD,
|
||||
isEnabled = true,
|
||||
data = buildJsonObject {
|
||||
put(key = "minLength", value = minLength)
|
||||
put(key = "minComplexity", value = minComplexity)
|
||||
put(key = "requireUpper", value = requireUpper)
|
||||
put(key = "requireLower", value = requireLower)
|
||||
put(key = "requireNumbers", value = requireNumbers)
|
||||
put(key = "requireSpecial", value = requireSpecial)
|
||||
put(key = "enforceOnLogin", value = true)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
@ -155,37 +154,4 @@ class AuthDiskSourceExtensionsTest {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `currentUserPoliciesListFlow should emit changes to current user's policy data`() =
|
||||
runTest {
|
||||
val userId = "userId1"
|
||||
val userStateJson = mockk<UserStateJson>() {
|
||||
every { activeUserId } returns userId
|
||||
}
|
||||
authDiskSource.apply {
|
||||
userState = userStateJson
|
||||
storePolicies(
|
||||
userId = userId,
|
||||
policies = listOf(createMockPolicy()),
|
||||
)
|
||||
}
|
||||
|
||||
authDiskSource.currentUserPoliciesListFlow.test {
|
||||
assertEquals(
|
||||
listOf(createMockPolicy()),
|
||||
awaitItem(),
|
||||
)
|
||||
|
||||
authDiskSource.storePolicies(
|
||||
userId = userId,
|
||||
policies = listOf(createMockPolicy(number = 3)),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
listOf(createMockPolicy(number = 3)),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class PolicyManagerTest {
|
||||
private val mutableUserStateFlow = MutableStateFlow<UserStateJson?>(null)
|
||||
private val mutablePolicyFlow = MutableStateFlow<List<SyncResponseJson.Policy>?>(null)
|
||||
private val authDiskSource: AuthDiskSource = mockk {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
every { getPoliciesFlow(USER_ID) } returns mutablePolicyFlow
|
||||
}
|
||||
|
||||
private lateinit var policyManager: PolicyManager
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
policyManager = PolicyManagerImpl(
|
||||
authDiskSource = authDiskSource,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `currentUserPoliciesListFlow should emit changes to current user's policy data`() =
|
||||
runTest {
|
||||
val userStateJson = mockk<UserStateJson> {
|
||||
every { activeUserId } returns USER_ID
|
||||
}
|
||||
val organizationsOne = createMockOrganization(
|
||||
number = 1,
|
||||
isEnabled = true,
|
||||
shouldUsePolicies = true,
|
||||
)
|
||||
val organizationsTwo = createMockOrganization(
|
||||
number = 2,
|
||||
isEnabled = true,
|
||||
shouldUsePolicies = true,
|
||||
)
|
||||
val expectedPolicyOne = createMockPolicy(
|
||||
isEnabled = true,
|
||||
number = 1,
|
||||
organizationId = organizationsOne.id,
|
||||
type = PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT,
|
||||
)
|
||||
val expectedPolicyTwo = createMockPolicy(
|
||||
isEnabled = true,
|
||||
number = 2,
|
||||
organizationId = organizationsTwo.id,
|
||||
type = PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT,
|
||||
)
|
||||
every {
|
||||
authDiskSource.getOrganizations(USER_ID)
|
||||
} returns listOf(organizationsOne) andThen listOf(organizationsTwo)
|
||||
|
||||
mutableUserStateFlow.value = userStateJson
|
||||
mutablePolicyFlow.value = listOf(expectedPolicyOne)
|
||||
|
||||
policyManager
|
||||
.getActivePoliciesFlow(type = PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT)
|
||||
.test {
|
||||
assertEquals(listOf(expectedPolicyOne), awaitItem())
|
||||
|
||||
mutablePolicyFlow.value = listOf(expectedPolicyTwo)
|
||||
|
||||
assertEquals(listOf(expectedPolicyTwo), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getActivePolicies returns empty list if user id is null`() {
|
||||
every {
|
||||
authDiskSource.userState
|
||||
} returns null
|
||||
|
||||
assertTrue(policyManager.getActivePolicies(type = PolicyTypeJson.MASTER_PASSWORD).isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getActivePolicies returns empty list if the policies are not active`() {
|
||||
val userState: UserStateJson = mockk {
|
||||
every { activeUserId } returns USER_ID
|
||||
}
|
||||
every { authDiskSource.userState } returns userState
|
||||
every {
|
||||
authDiskSource.getOrganizations(USER_ID)
|
||||
} returns listOf(
|
||||
createMockOrganization(
|
||||
number = 3,
|
||||
isEnabled = true,
|
||||
),
|
||||
)
|
||||
every {
|
||||
authDiskSource.getPolicies(USER_ID)
|
||||
} returns listOf(
|
||||
createMockPolicy(
|
||||
organizationId = "mockId-3",
|
||||
isEnabled = true,
|
||||
),
|
||||
)
|
||||
|
||||
assertTrue(policyManager.getActivePolicies(type = PolicyTypeJson.MASTER_PASSWORD).isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getActivePolicies returns active and applied policies`() {
|
||||
val userState: UserStateJson = mockk {
|
||||
every { activeUserId } returns USER_ID
|
||||
}
|
||||
every { authDiskSource.userState } returns userState
|
||||
every {
|
||||
authDiskSource.getOrganizations(USER_ID)
|
||||
} returns listOf(
|
||||
createMockOrganization(
|
||||
number = 3,
|
||||
isEnabled = false,
|
||||
),
|
||||
)
|
||||
every {
|
||||
authDiskSource.getPolicies(USER_ID)
|
||||
} returns listOf(
|
||||
createMockPolicy(
|
||||
organizationId = "mockId-3",
|
||||
isEnabled = true,
|
||||
),
|
||||
)
|
||||
|
||||
assertTrue(policyManager.getActivePolicies(type = PolicyTypeJson.MASTER_PASSWORD).isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
private const val USER_ID = "userId"
|
|
@ -19,6 +19,7 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.TrustedDeviceUserD
|
|||
import com.x8bit.bitwarden.data.auth.datasource.network.model.UserDecryptionOptionsJson
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.PasswordHistoryDiskSource
|
||||
|
@ -72,6 +73,7 @@ class GeneratorRepositoryTest {
|
|||
private val passwordHistoryDiskSource: PasswordHistoryDiskSource = mockk()
|
||||
private val vaultSdkSource: VaultSdkSource = mockk()
|
||||
private val dispatcherManager = FakeDispatcherManager()
|
||||
private val policyManager: PolicyManager = mockk()
|
||||
|
||||
private val repository = GeneratorRepositoryImpl(
|
||||
generatorSdkSource = generatorSdkSource,
|
||||
|
@ -80,6 +82,7 @@ class GeneratorRepositoryTest {
|
|||
passwordHistoryDiskSource = passwordHistoryDiskSource,
|
||||
vaultSdkSource = vaultSdkSource,
|
||||
dispatcherManager = dispatcherManager,
|
||||
policyManager = policyManager,
|
||||
)
|
||||
|
||||
@AfterEach
|
||||
|
@ -769,35 +772,35 @@ class GeneratorRepositoryTest {
|
|||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `getPasswordGeneratorPolicy returns default settings when no policies are present`() = runTest {
|
||||
val userId = "testUserId"
|
||||
coEvery { authDiskSource.userState?.activeUserId } returns userId
|
||||
coEvery { authDiskSource.getPolicies(userId) } returns emptyList()
|
||||
fun `getPasswordGeneratorPolicy returns default settings when no policies are present`() =
|
||||
runTest {
|
||||
every {
|
||||
policyManager.getActivePolicies(type = PolicyTypeJson.PASSWORD_GENERATOR)
|
||||
} returns emptyList()
|
||||
|
||||
val policy = repository.getPasswordGeneratorPolicy()
|
||||
val policy = repository.getPasswordGeneratorPolicy()
|
||||
|
||||
val expectedPolicy = PolicyInformation.PasswordGenerator(
|
||||
defaultType = "password",
|
||||
minLength = null,
|
||||
useUpper = false,
|
||||
useLower = false,
|
||||
useNumbers = false,
|
||||
useSpecial = false,
|
||||
minNumbers = null,
|
||||
minSpecial = null,
|
||||
minNumberWords = null,
|
||||
capitalize = false,
|
||||
includeNumber = false,
|
||||
)
|
||||
val expectedPolicy = PolicyInformation.PasswordGenerator(
|
||||
defaultType = "password",
|
||||
minLength = null,
|
||||
useUpper = false,
|
||||
useLower = false,
|
||||
useNumbers = false,
|
||||
useSpecial = false,
|
||||
minNumbers = null,
|
||||
minSpecial = null,
|
||||
minNumberWords = null,
|
||||
capitalize = false,
|
||||
includeNumber = false,
|
||||
)
|
||||
|
||||
assertNotNull(policy)
|
||||
assertEquals(expectedPolicy, policy)
|
||||
}
|
||||
assertNotNull(policy)
|
||||
assertEquals(expectedPolicy, policy)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `getPasswordGeneratorPolicy applies strictest settings from multiple policies`() = runTest {
|
||||
val userId = "testUserId"
|
||||
val policy1 = PolicyInformation.PasswordGenerator(
|
||||
defaultType = "password",
|
||||
minLength = 8,
|
||||
|
@ -840,8 +843,7 @@ class GeneratorRepositoryTest {
|
|||
organizationId = "id2",
|
||||
),
|
||||
)
|
||||
coEvery { authDiskSource.userState?.activeUserId } returns userId
|
||||
coEvery { authDiskSource.getPolicies(userId) } returns policies
|
||||
every { policyManager.getActivePolicies(type = PolicyTypeJson.PASSWORD_GENERATOR) } returns policies
|
||||
|
||||
val resultPolicy = repository.getPasswordGeneratorPolicy()
|
||||
|
||||
|
|
|
@ -7,12 +7,13 @@ import kotlinx.serialization.json.JsonObject
|
|||
*/
|
||||
fun createMockPolicy(
|
||||
number: Int = 1,
|
||||
organizationId: String = "mockOrganizationId-$number",
|
||||
type: PolicyTypeJson = PolicyTypeJson.MASTER_PASSWORD,
|
||||
isEnabled: Boolean = false,
|
||||
data: JsonObject? = null,
|
||||
): SyncResponseJson.Policy =
|
||||
SyncResponseJson.Policy(
|
||||
organizationId = "mockOrganizationId-$number",
|
||||
organizationId = organizationId,
|
||||
id = "mockId-$number",
|
||||
type = type,
|
||||
isEnabled = isEnabled,
|
||||
|
|
|
@ -30,13 +30,17 @@ fun createMockProfile(number: Int): SyncResponseJson.Profile =
|
|||
/**
|
||||
* Create a mock [SyncResponseJson.Profile.Organization] with a given [number].
|
||||
*/
|
||||
fun createMockOrganization(number: Int): SyncResponseJson.Profile.Organization =
|
||||
fun createMockOrganization(
|
||||
number: Int,
|
||||
isEnabled: Boolean = false,
|
||||
shouldUsePolicies: Boolean = false,
|
||||
): SyncResponseJson.Profile.Organization =
|
||||
SyncResponseJson.Profile.Organization(
|
||||
shouldUsePolicies = false,
|
||||
shouldUsePolicies = shouldUsePolicies,
|
||||
keyConnectorUrl = "mockKeyConnectorUrl-$number",
|
||||
type = 1,
|
||||
type = OrganizationType.ADMIN,
|
||||
seats = 1,
|
||||
isEnabled = false,
|
||||
isEnabled = isEnabled,
|
||||
providerType = 1,
|
||||
maxCollections = 1,
|
||||
isSelfHost = false,
|
||||
|
@ -60,7 +64,7 @@ fun createMockOrganization(number: Int): SyncResponseJson.Profile.Organization =
|
|||
name = "mockName-$number",
|
||||
shouldUseApi = false,
|
||||
familySponsorshipValidUntil = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
|
||||
status = 1,
|
||||
status = OrganizationStatusType.ACCEPTED,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,9 @@ import app.cash.turbine.test
|
|||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.exportvault.model.ExportVaultFormat
|
||||
|
@ -16,15 +19,21 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
|||
import org.junit.jupiter.api.Test
|
||||
|
||||
class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||
private val authRepository: AuthRepository = mockk {
|
||||
every { hasExportVaultPoliciesEnabled } returns false
|
||||
private val authRepository: AuthRepository = mockk()
|
||||
|
||||
private val policyManager: PolicyManager = mockk {
|
||||
every {
|
||||
getActivePolicies(type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT)
|
||||
} returns emptyList()
|
||||
}
|
||||
|
||||
private val savedStateHandle = SavedStateHandle()
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct`() = runTest {
|
||||
every { authRepository.hasExportVaultPoliciesEnabled } returns true
|
||||
every {
|
||||
policyManager.getActivePolicies(type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT)
|
||||
} returns listOf(createMockPolicy())
|
||||
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -185,6 +194,7 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
|||
private fun createViewModel(): ExportVaultViewModel =
|
||||
ExportVaultViewModel(
|
||||
authRepository = authRepository,
|
||||
policyManager = policyManager,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue