Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.x8bit.bitwarden.data.auth.repository.model

import com.bitwarden.network.model.SendTypeJson
import com.bitwarden.network.model.SendWhoCanAccessTypeJson
import com.bitwarden.network.model.SyncResponseJson
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -113,6 +115,42 @@ sealed class PolicyInformation {
val shouldDisableHideEmail: Boolean?,
) : PolicyInformation()

/**
* Represents a policy enforcing rules on the creation and sharing of Sends. Supersedes the
* disable-send policy and [SendOptions] when the `pm-31885-send-controls` feature flag is
* active.
*
* @property disableSend Whether the ability to create and edit Sends is disabled.
* @property disableHideEmail Whether the user should have the ability to hide their email
* address from Send recipients.
* @property whoCanAccess The access type Sends are restricted to, if any.
* @property allowedDomains A comma-separated list of email domains recipients must belong to
* when [whoCanAccess] is [SendWhoCanAccessTypeJson.SPECIFIC_PEOPLE].
* @property deletionHours The number of hours until a Send is deleted, if enforced.
* @property allowedSendTypes The types of Sends that are allowed to be created, if
* restricted.
*/
@Serializable
data class SendControls(
@SerialName("disableSend")
val disableSend: Boolean?,

@SerialName("disableHideEmail")
val disableHideEmail: Boolean?,

Comment thread
andrebispo5 marked this conversation as resolved.
@SerialName("whoCanAccess")
val whoCanAccess: SendWhoCanAccessTypeJson?,

@SerialName("allowedDomains")
val allowedDomains: String?,

@SerialName("deletionHours")
val deletionHours: Int?,

@SerialName("allowedSendTypes")
val allowedSendTypes: List<SendTypeJson>?,
) : PolicyInformation()

/**
* Represents a policy enforcing rules on the user's vault timeout settings.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ val PolicyView.policyInformation: PolicyInformation?
JSON.decodeFromStringOrNull<PolicyInformation.SendOptions>(it)
}

PolicyType.SEND_CONTROLS -> {
JSON.decodeFromStringOrNull<PolicyInformation.SendControls>(it)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is any spot in the app using this yet?


else -> null
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ inline fun <reified T : PolicyInformation> getPolicyType(): PolicyType =
PolicyInformation.MasterPassword::class.java -> PolicyType.MASTER_PASSWORD
PolicyInformation.PasswordGenerator::class.java -> PolicyType.PASSWORD_GENERATOR
PolicyInformation.SendOptions::class.java -> PolicyType.SEND_OPTIONS
PolicyInformation.SendControls::class.java -> PolicyType.SEND_CONTROLS
PolicyInformation.VaultTimeout::class.java -> PolicyType.MAXIMUM_VAULT_TIMEOUT

else -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.x8bit.bitwarden.data.auth.repository.util

import com.bitwarden.network.model.OrganizationType
import com.bitwarden.network.model.SendTypeJson
import com.bitwarden.network.model.SendWhoCanAccessTypeJson
import com.bitwarden.network.model.SyncResponseJson
import com.bitwarden.network.model.createMockOrganizationNetwork
import com.bitwarden.network.model.createMockPermissions
Expand Down Expand Up @@ -172,6 +174,27 @@ class SyncResponseJsonExtensionsTest {
)
}

@Test
fun `policyInformation converts the SendControls Json data to policy information`() {
val policyInformation = PolicyInformation.SendControls(
disableSend = false,
disableHideEmail = true,
whoCanAccess = SendWhoCanAccessTypeJson.SPECIFIC_PEOPLE,
allowedDomains = "bitwarden.com",
deletionHours = 168,
allowedSendTypes = listOf(SendTypeJson.TEXT),
)
val policy = createMockPolicyView(
type = PolicyType.SEND_CONTROLS,
data = Json.encodeToString(policyInformation),
)

assertEquals(
policyInformation,
policy.policyInformation,
)
}

@Test
fun `policyInformation returns null policy information for null data`() {
val masterPasswordPolicy = createMockPolicyView(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ class PolicyManagerExtensionsTest {
)
}

@Test
fun `getPolicyType with SendControls should map to appropriate PolicyTypeJson`() {
assertEquals(
PolicyType.SEND_CONTROLS,
getPolicyType<PolicyInformation.SendControls>(),
)
}

@Test
fun `getPolicyType with VaultTimeout should map to appropriate PolicyTypeJson`() {
assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ sealed class FlagKey<out T : Any> {
FillAssistTargetingRules,
PoliciesInAcceptedState,
FedRamp,
SendControls,
SendControlsExistingSends,
)
}
}
Expand Down Expand Up @@ -189,6 +191,23 @@ sealed class FlagKey<out T : Any> {
override val defaultValue: Boolean = false
}

/**
* Data object holding the feature flag key for the consolidated Send Controls policy.
*/
data object SendControls : FlagKey<Boolean>() {
override val keyName: String = "pm-31885-send-controls"
override val defaultValue: Boolean = false
}

/**
* Data object holding the feature flag key for enforcing the Send Controls policy against
* Sends created before the policy existed.
*/
data object SendControlsExistingSends : FlagKey<Boolean>() {
override val keyName: String = "pm-31885-send-controls-existing-sends"
override val defaultValue: Boolean = false
}

//region Dummy keys for testing
/**
* Data object holding the key for a [Boolean] flag to be used in tests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ class FlagKeyTest {
FlagKey.FedRamp.keyName,
"fedramp-gov-region",
)
assertEquals(
FlagKey.SendControls.keyName,
"pm-31885-send-controls",
)
assertEquals(
FlagKey.SendControlsExistingSends.keyName,
"pm-31885-send-controls-existing-sends",
)
}

@Test
Expand All @@ -84,6 +92,8 @@ class FlagKeyTest {
FlagKey.ManageDevices,
FlagKey.PoliciesInAcceptedState,
FlagKey.FedRamp,
FlagKey.SendControls,
FlagKey.SendControlsExistingSends,
).all {
!it.defaultValue
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.bitwarden.network.model

import androidx.annotation.Keep
import com.bitwarden.core.data.serializer.BaseEnumeratedIntSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Represents who is allowed to view a Send under the `SendControls` policy.
*/
@Serializable(SendWhoCanAccessTypeSerializer::class)
enum class SendWhoCanAccessTypeJson {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about just calling this SendAccessTypeJson?

/**
* Anyone with the link can view the Send.
*/
@SerialName("0")
ANY,

/**
* Only individuals with the password set on the Send can view it.
*/
@SerialName("1")
PASSWORD_PROTECTED,

/**
* Only specific people, identified by email, can view the Send.
*/
@SerialName("2")
SPECIFIC_PEOPLE,
}

@Keep
private class SendWhoCanAccessTypeSerializer :
BaseEnumeratedIntSerializer<SendWhoCanAccessTypeJson>(
className = "SendWhoCanAccessTypeJson",
values = SendWhoCanAccessTypeJson.entries.toTypedArray(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ fun <T : Any> FlagKey<T>.ListItemContent(
FlagKey.DebugDisableSelfHostPremiumCheck,
FlagKey.PoliciesInAcceptedState,
FlagKey.FedRamp,
FlagKey.SendControls,
FlagKey.SendControlsExistingSends,
-> {
@Suppress("UNCHECKED_CAST")
BooleanFlagItem(
Expand Down Expand Up @@ -104,4 +106,8 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
}

FlagKey.FedRamp -> stringResource(BitwardenString.fed_ramp)
FlagKey.SendControls -> stringResource(BitwardenString.send_controls)
FlagKey.SendControlsExistingSends -> {
stringResource(BitwardenString.send_controls_existing_sends)
}
}
2 changes: 2 additions & 0 deletions ui/src/main/res/values/strings_non_localized.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
<string name="debug_disable_self_host_premium_check">Debug: Disable self-host premium check</string>
<string name="policies_in_accepted_state">Policies in accepted state</string>
<string name="fed_ramp">FedRAMP</string>
<string name="send_controls">Send Controls</string>
<string name="send_controls_existing_sends">Send Controls - Existing Sends</string>

<!-- endregion Debug Menu -->
</resources>
Loading