PM-11299: Update the userState to properly parse the hasManageResetPasswordPermission flag (#3820)

This commit is contained in:
David Perez 2024-08-23 11:11:20 -05:00 committed by GitHub
parent 162da64567
commit b7330392cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 74 additions and 11 deletions

View file

@ -7,12 +7,15 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
*
* @property id The ID of the organization.
* @property name The name of the organization (if applicable).
* @property shouldManageResetPassword Indicates that this user has the permission to manage their
* own password.
* @property shouldUseKeyConnector Indicates that the organization uses a key connector.
* @property role The user's role in the organization.
*/
data class Organization(
val id: String,
val name: String?,
val shouldManageResetPassword: Boolean,
val shouldUseKeyConnector: Boolean,
val role: OrganizationType,
)

View file

@ -16,6 +16,7 @@ fun SyncResponseJson.Profile.Organization.toOrganization(): Organization =
name = this.name,
shouldUseKeyConnector = this.shouldUseKeyConnector,
role = this.type,
shouldManageResetPassword = this.permissions.shouldManageResetPassword,
)
/**

View file

@ -8,6 +8,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
import com.x8bit.bitwarden.data.platform.repository.util.toEnvironmentUrlsOrDefault
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
import com.x8bit.bitwarden.data.vault.repository.util.statusFor
@ -101,7 +102,7 @@ fun UserStateJson.toUserStateJsonWithPassword(): UserStateJson {
/**
* Converts the given [UserStateJson] to a [UserState] using the given [vaultState].
*/
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
fun UserStateJson.toUserState(
vaultState: List<VaultUnlockData>,
userAccountTokens: List<UserAccountTokens>,
@ -125,8 +126,17 @@ fun UserStateJson.toUserState(
val decryptionOptions = profile.userDecryptionOptions
val trustedDeviceOptions = decryptionOptions?.trustedDeviceUserDecryptionOptions
val keyConnectorOptions = decryptionOptions?.keyConnectorUserDecryptionOptions
val organizations = userOrganizationsList
.find { it.userId == userId }
?.organizations
.orEmpty()
val hasManageResetPasswordPermission = organizations.any {
it.role == OrganizationType.OWNER ||
it.role == OrganizationType.ADMIN ||
it.shouldManageResetPassword
}
val needsMasterPassword = decryptionOptions?.hasMasterPassword == false &&
trustedDeviceOptions?.hasManageResetPasswordPermission != false &&
hasManageResetPasswordPermission &&
keyConnectorOptions == null
val trustedDevice = trustedDeviceOptions?.let {
UserState.TrustedDevice(
@ -152,10 +162,7 @@ fun UserStateJson.toUserState(
?.isLoggedIn == true,
isVaultUnlocked = vaultUnlocked,
needsPasswordReset = needsPasswordReset,
organizations = userOrganizationsList
.find { it.userId == userId }
?.organizations
.orEmpty(),
organizations = organizations,
isBiometricsEnabled = isBiometricsEnabledProvider(userId),
vaultUnlockType = vaultUnlockTypeProvider(userId),
needsMasterPassword = needsMasterPassword,

View file

@ -4277,6 +4277,9 @@ class AuthRepositoryTest {
mockk<SyncResponseJson.Profile.Organization> {
every { id } returns "orgId"
every { name } returns "orgName"
every { permissions } returns mockk {
every { shouldManageResetPassword } returns false
}
every { shouldUseKeyConnector } returns true
every { type } returns OrganizationType.USER
every { keyConnectorUrl } returns null
@ -4299,6 +4302,9 @@ class AuthRepositoryTest {
mockk<SyncResponseJson.Profile.Organization> {
every { id } returns "orgId"
every { name } returns "orgName"
every { permissions } returns mockk {
every { shouldManageResetPassword } returns false
}
every { shouldUseKeyConnector } returns true
every { type } returns OrganizationType.USER
every { keyConnectorUrl } returns url
@ -4332,6 +4338,9 @@ class AuthRepositoryTest {
mockk<SyncResponseJson.Profile.Organization> {
every { id } returns "orgId"
every { name } returns "orgName"
every { permissions } returns mockk {
every { shouldManageResetPassword } returns false
}
every { shouldUseKeyConnector } returns true
every { type } returns OrganizationType.USER
every { keyConnectorUrl } returns url

View file

@ -189,6 +189,7 @@ class AuthDiskSourceExtensionsTest {
Organization(
id = "mockId-1",
name = "mockName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -200,6 +201,7 @@ class AuthDiskSourceExtensionsTest {
Organization(
id = "mockId-2",
name = "mockName-2",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -211,6 +213,7 @@ class AuthDiskSourceExtensionsTest {
Organization(
id = "mockId-3",
name = "mockName-3",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -357,6 +360,7 @@ class AuthDiskSourceExtensionsTest {
Organization(
id = "mockId-1",
name = "mockName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -387,6 +391,7 @@ class AuthDiskSourceExtensionsTest {
Organization(
id = "mockId-1",
name = "mockName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -398,6 +403,7 @@ class AuthDiskSourceExtensionsTest {
Organization(
id = "mockId-2",
name = "mockName-2",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -20,6 +20,7 @@ class SyncResponseJsonExtensionsTest {
Organization(
id = "mockId-1",
name = "mockName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -34,19 +35,22 @@ class SyncResponseJsonExtensionsTest {
Organization(
id = "mockId-1",
name = "mockName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = true,
role = OrganizationType.ADMIN,
),
Organization(
id = "mockId-2",
name = "mockName-2",
shouldManageResetPassword = true,
shouldUseKeyConnector = false,
role = OrganizationType.USER,
),
),
listOf(
createMockOrganization(number = 1).copy(shouldUseKeyConnector = true),
createMockOrganization(number = 2).copy(type = OrganizationType.USER),
createMockOrganization(number = 2, shouldManageResetPassword = true)
.copy(type = OrganizationType.USER),
)
.toOrganizations(),
)

View file

@ -342,6 +342,7 @@ class UserStateJsonExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -403,6 +404,7 @@ class UserStateJsonExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -444,6 +446,7 @@ class UserStateJsonExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -501,6 +504,7 @@ class UserStateJsonExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -543,13 +547,14 @@ class UserStateJsonExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
),
isBiometricsEnabled = false,
vaultUnlockType = VaultUnlockType.MASTER_PASSWORD,
needsMasterPassword = false,
needsMasterPassword = true,
trustedDevice = UserState.TrustedDevice(
isDeviceTrusted = true,
hasAdminApproval = false,
@ -608,6 +613,7 @@ class UserStateJsonExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -34,6 +34,7 @@ fun createMockOrganization(
number: Int,
isEnabled: Boolean = false,
shouldUsePolicies: Boolean = false,
shouldManageResetPassword: Boolean = false,
): SyncResponseJson.Profile.Organization =
SyncResponseJson.Profile.Organization(
shouldUsePolicies = shouldUsePolicies,
@ -45,7 +46,7 @@ fun createMockOrganization(
providerType = 1,
maxCollections = 1,
isSelfHost = false,
permissions = createMockPermissions(),
permissions = createMockPermissions(shouldManageResetPassword = shouldManageResetPassword),
providerId = "mockProviderId-$number",
id = "mockId-$number",
shouldUseGroups = false,
@ -78,10 +79,12 @@ fun createMockOrganizationKeys(number: Int): Map<String, String> =
/**
* Create a mock [SyncResponseJson.Profile.Permissions].
*/
fun createMockPermissions(): SyncResponseJson.Profile.Permissions =
fun createMockPermissions(
shouldManageResetPassword: Boolean = false,
): SyncResponseJson.Profile.Permissions =
SyncResponseJson.Profile.Permissions(
shouldManageGroups = false,
shouldManageResetPassword = false,
shouldManageResetPassword = shouldManageResetPassword,
shouldAccessReports = false,
shouldManagePolicies = false,
shouldDeleteAnyCollection = false,

View file

@ -156,6 +156,7 @@ private val DEFAULT_ACCOUNT = UserState.Account(
Organization(
id = "orgId",
name = ORGANIZATION_NAME,
shouldManageResetPassword = false,
shouldUseKeyConnector = true,
role = OrganizationType.USER,
),

View file

@ -341,6 +341,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
Organization(
id = "orgId",
name = "orgName",
shouldManageResetPassword = false,
shouldUseKeyConnector = true,
role = OrganizationType.USER,
),

View file

@ -3879,6 +3879,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -435,6 +435,7 @@ class CipherViewExtensionsTest {
Organization(
id = "mockOrganizationId-1",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -491,18 +491,21 @@ private val DEFAULT_USER_STATE = UserState(
Organization(
id = "mockOrganizationId-1",
name = "mockOrganizationName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
Organization(
id = "mockOrganizationId-2",
name = "mockOrganizationName-2",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
Organization(
id = "mockOrganizationId-3",
name = "mockOrganizationName-3",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -103,18 +103,21 @@ private fun createMockUserState(hasOrganizations: Boolean = true): UserState =
Organization(
id = "mockOrganizationId-1",
name = "mockOrganizationName-1",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
Organization(
id = "mockOrganizationId-2",
name = "mockOrganizationName-2",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
Organization(
id = "mockOrganizationId-3",
name = "mockOrganizationName-3",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -188,6 +188,7 @@ class VaultViewModelTest : BaseViewModelTest() {
Organization(
id = "organiationId",
name = "Test Organization",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -271,6 +272,7 @@ class VaultViewModelTest : BaseViewModelTest() {
Organization(
id = "organizationId",
name = "Test Organization",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -478,6 +480,7 @@ class VaultViewModelTest : BaseViewModelTest() {
Organization(
id = "testOrganizationId",
name = "Test Organization",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),

View file

@ -77,6 +77,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -101,6 +102,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -129,6 +131,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -157,6 +160,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -200,6 +204,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -241,6 +246,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -286,6 +292,7 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId",
name = "organizationName",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -360,11 +367,13 @@ class UserStateExtensionsTest {
id = "organizationId-B",
name = "Organization B",
shouldUseKeyConnector = false,
shouldManageResetPassword = false,
role = OrganizationType.ADMIN,
),
Organization(
id = "organizationId-A",
name = "Organization A",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
@ -413,12 +422,14 @@ class UserStateExtensionsTest {
Organization(
id = "organizationId-B",
name = "Organization B",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),
Organization(
id = "organizationId-A",
name = "Organization A",
shouldManageResetPassword = false,
shouldUseKeyConnector = false,
role = OrganizationType.ADMIN,
),