[PM-20069] Migrate CiphersApi to network module (#5021)

This commit is contained in:
Patrick Honkonen
2025-04-10 17:09:21 -04:00
committed by GitHub
parent d7f771990e
commit 392695cb54
122 changed files with 282 additions and 277 deletions

View File

@@ -0,0 +1,158 @@
package com.bitwarden.network.api
import com.bitwarden.network.model.AttachmentJsonRequest
import com.bitwarden.network.model.AttachmentJsonResponse
import com.bitwarden.network.model.CipherJsonRequest
import com.bitwarden.network.model.CreateCipherInOrganizationJsonRequest
import com.bitwarden.network.model.ImportCiphersJsonRequest
import com.bitwarden.network.model.NetworkResult
import com.bitwarden.network.model.ShareCipherJsonRequest
import com.bitwarden.network.model.SyncResponseJson
import com.bitwarden.network.model.UpdateCipherCollectionsJsonRequest
import okhttp3.MultipartBody
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
/**
* Defines raw calls under the /ciphers API with authentication applied.
*/
@Suppress("TooManyFunctions")
interface CiphersApi {
/**
* Create a cipher.
*/
@POST("ciphers")
suspend fun createCipher(@Body body: CipherJsonRequest): NetworkResult<SyncResponseJson.Cipher>
/**
* Create a cipher that belongs to an organization.
*/
@POST("ciphers/create")
suspend fun createCipherInOrganization(
@Body body: CreateCipherInOrganizationJsonRequest,
): NetworkResult<SyncResponseJson.Cipher>
/**
* Associates an attachment with a cipher.
*/
@POST("ciphers/{cipherId}/attachment/v2")
suspend fun createAttachment(
@Path("cipherId") cipherId: String,
@Body body: AttachmentJsonRequest,
): NetworkResult<AttachmentJsonResponse>
/**
* Uploads the attachment associated with a cipher.
*/
@POST("ciphers/{cipherId}/attachment/{attachmentId}")
suspend fun uploadAttachment(
@Path("cipherId") cipherId: String,
@Path("attachmentId") attachmentId: String,
@Body body: MultipartBody,
): NetworkResult<Unit>
/**
* Updates a cipher.
*/
@PUT("ciphers/{cipherId}")
suspend fun updateCipher(
@Path("cipherId") cipherId: String,
@Body body: CipherJsonRequest,
): NetworkResult<SyncResponseJson.Cipher>
/**
* Shares a cipher.
*/
@PUT("ciphers/{cipherId}/share")
suspend fun shareCipher(
@Path("cipherId") cipherId: String,
@Body body: ShareCipherJsonRequest,
): NetworkResult<SyncResponseJson.Cipher>
/**
* Shares an attachment.
*/
@POST("ciphers/{cipherId}/attachment/{attachmentId}/share")
suspend fun shareAttachment(
@Path("cipherId") cipherId: String,
@Path("attachmentId") attachmentId: String,
@Query("organizationId") organizationId: String?,
@Body body: MultipartBody,
): NetworkResult<Unit>
/**
* Updates a cipher's collections.
*/
@PUT("ciphers/{cipherId}/collections")
suspend fun updateCipherCollections(
@Path("cipherId") cipherId: String,
@Body body: UpdateCipherCollectionsJsonRequest,
): NetworkResult<Unit>
/**
* Hard deletes a cipher.
*/
@DELETE("ciphers/{cipherId}")
suspend fun hardDeleteCipher(
@Path("cipherId") cipherId: String,
): NetworkResult<Unit>
/**
* Soft deletes a cipher.
*/
@PUT("ciphers/{cipherId}/delete")
suspend fun softDeleteCipher(
@Path("cipherId") cipherId: String,
): NetworkResult<Unit>
/**
* Deletes an attachment from a cipher.
*/
@DELETE("ciphers/{cipherId}/attachment/{attachmentId}")
suspend fun deleteCipherAttachment(
@Path("cipherId") cipherId: String,
@Path("attachmentId") attachmentId: String,
): NetworkResult<Unit>
/**
* Restores a cipher.
*/
@PUT("ciphers/{cipherId}/restore")
suspend fun restoreCipher(
@Path("cipherId") cipherId: String,
): NetworkResult<SyncResponseJson.Cipher>
/**
* Gets a cipher.
*/
@GET("ciphers/{cipherId}")
suspend fun getCipher(
@Path("cipherId") cipherId: String,
): NetworkResult<SyncResponseJson.Cipher>
/**
* Gets a cipher attachment.
*/
@GET("ciphers/{cipherId}/attachment/{attachmentId}")
suspend fun getCipherAttachment(
@Path("cipherId") cipherId: String,
@Path("attachmentId") attachmentId: String,
): NetworkResult<SyncResponseJson.Cipher.Attachment>
/**
* Indicates if the active user has unassigned ciphers.
*/
@GET("ciphers/has-unassigned-ciphers")
suspend fun hasUnassignedCiphers(): NetworkResult<Boolean>
@POST("ciphers/import")
suspend fun importCiphers(
@Body body: ImportCiphersJsonRequest,
): NetworkResult<Unit>
}

View File

@@ -0,0 +1,19 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents a request to create an attachment.
*/
@Serializable
data class AttachmentJsonRequest(
@SerialName("fileName")
val fileName: String?,
@SerialName("key")
val key: String?,
@SerialName("fileSize")
val fileSize: String?,
)

View File

@@ -0,0 +1,22 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents the JSON response from creating a new attachment.
*/
@Serializable
data class AttachmentJsonResponse(
@SerialName("attachmentId")
val attachmentId: String,
@SerialName("url")
val url: String,
@SerialName("fileUploadType")
val fileUploadType: FileUploadType,
@SerialName("cipherResponse")
val cipherResponse: SyncResponseJson.Cipher,
)

View File

@@ -0,0 +1,80 @@
package com.bitwarden.network.model
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.time.ZonedDateTime
/**
* Represents a cipher request.
*
* @property notes The notes of the cipher (nullable).
* @property reprompt The reprompt of the cipher.
* @property passwordHistory A list of password history objects
* associated with the cipher (nullable).
* @property type The type of cipher.
* @property login The login of the cipher.
* @property secureNote The secure note of the cipher.
* @property folderId The folder ID of the cipher (nullable).
* @property organizationId The organization ID of the cipher (nullable).
* @property identity The identity of the cipher.
* @property name The name of the cipher (nullable).
* @property fields A list of fields associated with the cipher (nullable).
* @property isFavorite If the cipher is a favorite.
* @property card The card of the cipher.
* @property key The key of the cipher (nullable).
*/
@Serializable
data class CipherJsonRequest(
@SerialName("notes")
val notes: String?,
@SerialName("attachments2")
val attachments: Map<String, AttachmentJsonRequest>?,
@SerialName("reprompt")
val reprompt: CipherRepromptTypeJson,
@SerialName("passwordHistory")
val passwordHistory: List<SyncResponseJson.Cipher.PasswordHistory>?,
@SerialName("lastKnownRevisionDate")
@Contextual
val lastKnownRevisionDate: ZonedDateTime?,
@SerialName("type")
val type: CipherTypeJson,
@SerialName("login")
val login: SyncResponseJson.Cipher.Login?,
@SerialName("secureNote")
val secureNote: SyncResponseJson.Cipher.SecureNote?,
@SerialName("sshKey")
val sshKey: SyncResponseJson.Cipher.SshKey?,
@SerialName("folderId")
val folderId: String?,
@SerialName("organizationId")
val organizationId: String?,
@SerialName("identity")
val identity: SyncResponseJson.Cipher.Identity?,
@SerialName("name")
val name: String?,
@SerialName("fields")
val fields: List<SyncResponseJson.Cipher.Field>?,
@SerialName("favorite")
val isFavorite: Boolean,
@SerialName("card")
val card: SyncResponseJson.Cipher.Card?,
@SerialName("key")
val key: String?,
)

View File

@@ -0,0 +1,30 @@
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 different types of cipher repromt.
*/
@Serializable(CipherRepromptTypeSerializer::class)
enum class CipherRepromptTypeJson {
/**
* No re-prompt is necessary.
*/
@SerialName("0")
NONE,
/**
* The user should be prompted for their master password prior to using the cipher password.
*/
@SerialName("1")
PASSWORD,
}
@Keep
private class CipherRepromptTypeSerializer : BaseEnumeratedIntSerializer<CipherRepromptTypeJson>(
className = "CipherRepromptTypeJson",
values = CipherRepromptTypeJson.entries.toTypedArray(),
)

View File

@@ -0,0 +1,48 @@
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 different types of ciphers.
*/
@Serializable(CipherTypeSerializer::class)
enum class CipherTypeJson {
/**
* A login containing a username and password.
*/
@SerialName("1")
LOGIN,
/**
* A secure note.
*/
@SerialName("2")
SECURE_NOTE,
/**
* A credit/debit card.
*/
@SerialName("3")
CARD,
/**
* Personal information for filling out forms.
*/
@SerialName("4")
IDENTITY,
/**
* A SSH key.
*/
@SerialName("5")
SSH_KEY,
}
@Keep
private class CipherTypeSerializer : BaseEnumeratedIntSerializer<CipherTypeJson>(
className = "CipherTypeJson",
values = CipherTypeJson.entries.toTypedArray(),
)

View File

@@ -0,0 +1,19 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents a create cipher in organization request.
*
* @property cipher The cipher to create.
* @property collectionIds A list of collection ids associated with the cipher.
*/
@Serializable
data class CreateCipherInOrganizationJsonRequest(
@SerialName("Cipher")
val cipher: CipherJsonRequest,
@SerialName("CollectionIds")
val collectionIds: List<String>,
)

View File

@@ -0,0 +1,19 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents the JSON response from creating a new file send.
*/
@Serializable
data class CreateFileSendResponseJson(
@SerialName("url")
val url: String,
@SerialName("fileUploadType")
val fileUploadType: FileUploadType,
@SerialName("sendResponse")
val sendResponse: SyncResponseJson.Send,
)

View File

@@ -0,0 +1,42 @@
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 different types of fields.
*/
@Serializable(FieldTypeSerializer::class)
enum class FieldTypeJson {
/**
* The field stores freeform input.
*/
@SerialName("0")
TEXT,
/**
* The field stores freeform input that is hidden from view.
*/
@SerialName("1")
HIDDEN,
/**
* The field stores a boolean value.
*/
@SerialName("2")
BOOLEAN,
/**
* The field value is linked to the item's username or password.
*/
@SerialName("3")
LINKED,
}
@Keep
private class FieldTypeSerializer : BaseEnumeratedIntSerializer<FieldTypeJson>(
className = "FieldTypeJson",
values = FieldTypeJson.entries.toTypedArray(),
)

View File

@@ -0,0 +1,24 @@
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 the type of file upload that should be used.
*/
@Serializable(FileUploadTypeSerializer::class)
enum class FileUploadType {
@SerialName("0")
DIRECT,
@SerialName("1")
AZURE,
}
@Keep
private class FileUploadTypeSerializer : BaseEnumeratedIntSerializer<FileUploadType>(
className = "FileUploadType",
values = FileUploadType.entries.toTypedArray(),
)

View File

@@ -0,0 +1,37 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents an import ciphers request.
*
* @property folders A list of folders to import.
* @property ciphers A list of ciphers to import.
* @property folderRelationships A map of cipher folder relationships to import. Key correlates to
* the index of the cipher in the ciphers list. Value correlates to the index of the folder in the
* folders list.
*/
@Serializable
data class ImportCiphersJsonRequest(
@SerialName("folders")
val folders: List<FolderWithIdJsonRequest>,
@SerialName("ciphers")
val ciphers: List<CipherJsonRequest>,
@SerialName("folderRelationships")
val folderRelationships: Map<Int, Int>,
) {
/**
* Represents a folder request with an optional [id] if the folder already exists.
*
* @property name The name of the folder.
* @property id The ID of the folder, if it already exists. Null otherwise.
**/
@Serializable
data class FolderWithIdJsonRequest(
@SerialName("name")
val name: String?,
@SerialName("id")
val id: String?,
)
}

View File

@@ -0,0 +1,186 @@
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 different fields that a custom cipher field can be linked to.
*/
@Serializable(LinkedIdTypeSerializer::class)
enum class LinkedIdTypeJson(val value: UInt) {
// region LOGIN
/**
* The field is linked to the login's username.
*/
@SerialName("100")
LOGIN_USERNAME(value = 100U),
/**
* The field is linked to the login's password.
*/
@SerialName("101")
LOGIN_PASSWORD(value = 101U),
// endregion LOGIN
// region CARD
/**
* The field is linked to the card's cardholder name.
*/
@SerialName("300")
CARD_CARDHOLDER_NAME(value = 300U),
/**
* The field is linked to the card's expiration month.
*/
@SerialName("301")
CARD_EXP_MONTH(value = 301U),
/**
* The field is linked to the card's expiration year.
*/
@SerialName("302")
CARD_EXP_YEAR(value = 302U),
/**
* The field is linked to the card's code.
*/
@SerialName("303")
CARD_CODE(value = 303U),
/**
* The field is linked to the card's brand.
*/
@SerialName("304")
CARD_BRAND(value = 304U),
/**
* The field is linked to the card's number.
*/
@SerialName("305")
CARD_NUMBER(value = 305U),
// endregion CARD
// region IDENTITY
/**
* The field is linked to the identity's title.
*/
@SerialName("400")
IDENTITY_TITLE(value = 400U),
/**
* The field is linked to the identity's middle name.
*/
@SerialName("401")
IDENTITY_MIDDLE_NAME(value = 401U),
/**
* The field is linked to the identity's address line 1.
*/
@SerialName("402")
IDENTITY_ADDRESS_1(value = 402U),
/**
* The field is linked to the identity's address line 2.
*/
@SerialName("403")
IDENTITY_ADDRESS_2(value = 403U),
/**
* The field is linked to the identity's address line 3.
*/
@SerialName("404")
IDENTITY_ADDRESS_3(value = 404U),
/**
* The field is linked to the identity's city.
*/
@SerialName("405")
IDENTITY_CITY(value = 405U),
/**
* The field is linked to the identity's state.
*/
@SerialName("406")
IDENTITY_STATE(value = 406U),
/**
* The field is linked to the identity's postal code
*/
@SerialName("407")
IDENTITY_POSTAL_CODE(value = 407U),
/**
* The field is linked to the identity's country.
*/
@SerialName("408")
IDENTITY_COUNTRY(value = 408U),
/**
* The field is linked to the identity's company.
*/
@SerialName("409")
IDENTITY_COMPANY(value = 409U),
/**
* The field is linked to the identity's email.
*/
@SerialName("410")
IDENTITY_EMAIL(value = 410U),
/**
* The field is linked to the identity's phone.
*/
@SerialName("411")
IDENTITY_PHONE(value = 411U),
/**
* The field is linked to the identity's SSN.
*/
@SerialName("412")
IDENTITY_SSN(value = 412U),
/**
* The field is linked to the identity's username.
*/
@SerialName("413")
IDENTITY_USERNAME(value = 413U),
/**
* The field is linked to the identity's passport number.
*/
@SerialName("414")
IDENTITY_PASSPORT_NUMBER(value = 414U),
/**
* The field is linked to the identity's license number.
*/
@SerialName("415")
IDENTITY_LICENSE_NUMBER(value = 415U),
/**
* The field is linked to the identity's first name.
*/
@SerialName("416")
IDENTITY_FIRST_NAME(value = 416U),
/**
* The field is linked to the identity's last name.
*/
@SerialName("417")
IDENTITY_LAST_NAME(value = 417U),
/**
* The field is linked to the identity's full name.
*/
@SerialName("418")
IDENTITY_FULL_NAME(value = 418U),
// endregion IDENTITY
}
@Keep
private class LinkedIdTypeSerializer : BaseEnumeratedIntSerializer<LinkedIdTypeJson>(
className = "LinkedIdTypeJson",
values = LinkedIdTypeJson.entries.toTypedArray(),
)

View File

@@ -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 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>(
className = "OrganizationStatusType",
values = OrganizationStatusType.entries.toTypedArray(),
)

View File

@@ -0,0 +1,48 @@
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 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>(
className = "OrganizationType",
values = OrganizationType.entries.toTypedArray(),
)

View File

@@ -0,0 +1,106 @@
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 different types of policies.
*/
@Serializable(PolicyTypeSerializer::class)
enum class PolicyTypeJson {
/**
* Requires users to have 2FA enabled.
*/
@SerialName("0")
TWO_FACTOR_AUTHENTICATION,
/**
* Sets minimum requirements for master password complexity.
*/
@SerialName("1")
MASTER_PASSWORD,
/**
* Sets minimum requirements/default type for generated passwords/passphrases.
*/
@SerialName("2")
PASSWORD_GENERATOR,
/**
* Allows users to only be apart of one organization.
*/
@SerialName("3")
ONLY_ORG,
/**
* Requires users to authenticate with SSO.
*/
@SerialName("4")
REQUIRE_SSO,
/**
* Disables personal vault ownership for adding/cloning items.
*/
@SerialName("5")
PERSONAL_OWNERSHIP,
/**
* Disables the ability to create and edit Sends.
*/
@SerialName("6")
DISABLE_SEND,
/**
* Sets restrictions or defaults for Bitwarden Sends.
*/
@SerialName("7")
SEND_OPTIONS,
/**
* Allows orgs to use reset password : also can enable auto-enrollment during invite flow.
*/
@SerialName("8")
RESET_PASSWORD,
/**
* Sets the maximum allowed vault timeout.
*/
@SerialName("9")
MAXIMUM_VAULT_TIMEOUT,
/**
* Disable personal vault export.
*/
@SerialName("10")
DISABLE_PERSONAL_VAULT_EXPORT,
/**
* Activate the auto-fill in the browser extension. Currently unused in mobile.
*/
@SerialName("11")
ACTIVATE_AUTOFILL,
/**
* Hides the setting to "Unlock with Pin".
*/
@SerialName("14")
REMOVE_UNLOCK_WITH_PIN,
/**
* Represents an unknown policy type.
*
* This is used for forward compatibility to handle new policy types that the client doesn't yet
* understand.
*/
@SerialName("-1")
UNKNOWN,
}
@Keep
private class PolicyTypeSerializer : BaseEnumeratedIntSerializer<PolicyTypeJson>(
className = "PolicyTypeJson",
values = PolicyTypeJson.entries.toTypedArray(),
default = PolicyTypeJson.UNKNOWN,
)

View File

@@ -0,0 +1,24 @@
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 different types of secure notes.
*/
@Serializable(SecureNoteTypeSerializer::class)
enum class SecureNoteTypeJson {
/**
* A generic note.
*/
@SerialName("0")
GENERIC,
}
@Keep
private class SecureNoteTypeSerializer : BaseEnumeratedIntSerializer<SecureNoteTypeJson>(
className = "SecureNoteTypeJson",
values = SecureNoteTypeJson.entries.toTypedArray(),
)

View File

@@ -0,0 +1,67 @@
package com.bitwarden.network.model
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.time.ZonedDateTime
/**
* Represents a send request.
*
* @property type The type of send.
* @property name The name of the send (nullable).
* @property notes The notes of the send (nullable).
* @property key The send key.
* @property maxAccessCount The maximum number of people who can access this send (nullable).
* @property expirationDate The date in which the send will expire (nullable).
* @property deletionDate The date in which the send will be deleted.
* @property file The file associated with this send (nullable).
* @property fileLength The length of the file in bytes (nullable).
* @property text The text associated with this send (nullable).
* @property password The password protecting this send (nullable).
* @property isDisabled Indicate if this send is disabled.
* @property shouldHideEmail Should the email address of the sender be hidden (nullable).
*/
@Serializable
data class SendJsonRequest(
@SerialName("type")
val type: SendTypeJson,
@SerialName("name")
val name: String?,
@SerialName("notes")
val notes: String?,
@SerialName("key")
val key: String,
@SerialName("maxAccessCount")
val maxAccessCount: Int?,
@SerialName("expirationDate")
@Contextual
val expirationDate: ZonedDateTime?,
@SerialName("deletionDate")
@Contextual
val deletionDate: ZonedDateTime,
@SerialName("fileLength")
val fileLength: Long?,
@SerialName("file")
val file: SyncResponseJson.Send.File?,
@SerialName("text")
val text: SyncResponseJson.Send.Text?,
@SerialName("password")
val password: String?,
@SerialName("disabled")
val isDisabled: Boolean,
@SerialName("hideEmail")
val shouldHideEmail: Boolean?,
)

View File

@@ -0,0 +1,30 @@
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 different types of send.
*/
@Serializable(SendTypeSerializer::class)
enum class SendTypeJson {
/**
* The send contains text data.
*/
@SerialName("0")
TEXT,
/**
* The send contains an attached file.
*/
@SerialName("1")
FILE,
}
@Keep
private class SendTypeSerializer : BaseEnumeratedIntSerializer<SendTypeJson>(
className = "SendTypeJson",
values = SendTypeJson.entries.toTypedArray(),
)

View File

@@ -0,0 +1,19 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents a share cipher request.
*
* @property cipher The cipher to share.
* @property collectionIds A list of collection ids associated with the cipher.
*/
@Serializable
data class ShareCipherJsonRequest(
@SerialName("Cipher")
val cipher: CipherJsonRequest,
@SerialName("CollectionIds")
val collectionIds: List<String>,
)

View File

@@ -0,0 +1,986 @@
package com.bitwarden.network.model
import kotlinx.serialization.Contextual
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import kotlinx.serialization.json.JsonObject
import java.time.ZonedDateTime
private const val DEFAULT_FIDO_2_KEY_TYPE = "public-key"
private const val DEFAULT_FIDO_2_KEY_ALGORITHM = "ECDSA"
private const val DEFAULT_FIDO_2_KEY_CURVE = "P-256"
/**
* Represents the response model for vault data fetched from the server.
*
* @property folders A list of folders associated with the vault data (nullable).
* @property collections A list of collections associated with the vault data (nullable).
* @property profile The profile associated with the vault data.
* @property ciphers A list of ciphers associated with the vault data (nullable).
* @property policies A list of policies associated with the vault data (nullable).
* @property domains A domains object associated with the vault data.
* @property sends A list of send objects associated with the vault data (nullable).
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class SyncResponseJson(
@SerialName("folders")
val folders: List<Folder>?,
@SerialName("collections")
val collections: List<Collection>?,
@SerialName("profile")
@JsonNames("Profile")
val profile: Profile,
@SerialName("ciphers")
val ciphers: List<Cipher>?,
@SerialName("policies")
val policies: List<Policy>?,
@SerialName("domains")
@JsonNames("Domains")
val domains: Domains?,
@SerialName("sends")
val sends: List<Send>?,
) {
/**
* Represents domains in the vault response.
*
* @property globalEquivalentDomains A list of global equivalent domains (nullable).
* @property equivalentDomains List of equivalent domains (nullable).
*/
@Serializable
data class Domains(
@SerialName("globalEquivalentDomains")
val globalEquivalentDomains: List<GlobalEquivalentDomain>?,
@SerialName("equivalentDomains")
val equivalentDomains: List<List<String>>?,
) {
/**
* Represents the global equivalent domain in the vault response.
*
* @property isExcluded If the global equivalent domain is excluded.
* @property domains A List of domains associated with
* the global equivalent domain (nullable).
* @property type The type of global equivalent domain.
*/
@Serializable
data class GlobalEquivalentDomain(
@SerialName("excluded")
val isExcluded: Boolean,
@SerialName("domains")
val domains: List<String>?,
@SerialName("type")
val type: Int,
)
}
/**
* Represents a folder in the vault response.
*
* @property revisionDate The revision date of the folder.
* @property name The name of the folder (nullable).
* @property id The ID of the folder.
*/
@Serializable
data class Folder(
@SerialName("revisionDate")
@Contextual
val revisionDate: ZonedDateTime,
@SerialName("name")
val name: String?,
@SerialName("id")
val id: String,
)
/**
* Represents a policy in the vault response.
*
* @property organizationId The organization ID of the policy.
* @property id The ID of the policy.
* @property type The type of policy.
* @property isEnabled If the policy is enabled or not.
* @property data Any extra data about the policy, in the form of a JSON string.
*/
@Serializable
data class Policy(
@SerialName("organizationId")
val organizationId: String,
@SerialName("id")
val id: String,
@SerialName("type")
val type: PolicyTypeJson,
@SerialName("enabled")
val isEnabled: Boolean,
@SerialName("data")
val data: JsonObject?,
)
/**
* Represents a profile in the vault response.
*
* @property providerOrganizations A list of provider organizations
* associated with the profile (nullable).
* @property isPremiumFromOrganization If the profile is premium from organization.
* @property shouldForcePasswordReset If the profile should force password reset.
* @property avatarColor The avatar color of the profile (nullable).
* @property isEmailVerified If the profile has a verified email.
* @property isTwoFactorEnabled If the profile has two factor authentication enabled.
* @property privateKey The private key of the profile (nullable).
* @property isPremium If the profile is premium.
* @property culture The culture of the profile (nullable).
* @property name The name of the profile (nullable).
* @property organizations A list of organizations associated with the profile (nullable).
* @property shouldUseKeyConnector If the profile should use a key connector.
* @property id The ID of the profile.
* @property masterPasswordHint The master password hint of the profile (nullable).
* @property email The email of the profile (nullable).
* @property key The key of the profile (nullable).
* @property securityStamp The secure stamp of the profile (nullable).
* @property providers A list of providers associated with the profile (nullable).
* @property creationDate The creation date of the account.
*/
@Serializable
data class Profile(
@SerialName("providerOrganizations")
val providerOrganizations: List<Organization>?,
@SerialName("premiumFromOrganization")
val isPremiumFromOrganization: Boolean,
@SerialName("forcePasswordReset")
val shouldForcePasswordReset: Boolean,
@SerialName("avatarColor")
val avatarColor: String?,
@SerialName("emailVerified")
val isEmailVerified: Boolean,
@SerialName("twoFactorEnabled")
val isTwoFactorEnabled: Boolean,
@SerialName("privateKey")
val privateKey: String?,
@SerialName("premium")
val isPremium: Boolean,
@SerialName("culture")
val culture: String?,
@SerialName("name")
val name: String?,
@SerialName("organizations")
val organizations: List<Organization>?,
@SerialName("usesKeyConnector")
val shouldUseKeyConnector: Boolean,
@SerialName("id")
val id: String,
@SerialName("masterPasswordHint")
val masterPasswordHint: String?,
@SerialName("email")
val email: String?,
@SerialName("key")
val key: String?,
@SerialName("securityStamp")
val securityStamp: String?,
@SerialName("providers")
val providers: List<Provider>?,
@SerialName("creationDate")
@Contextual
val creationDate: ZonedDateTime,
) {
/**
* Represents an organization in the vault response.
*
* @property shouldUsePolicies If the organization should use policies.
* @property keyConnectorUrl The key connector URL of the organization (nullable).
* @property type The type of organization.
* @property seats The number of seats in the organization (nullable).
* @property isEnabled If the organization is enabled.
* @property providerType They type of provider for the organization (nullable).
* @property maxCollections The max collections of the organization (nullable).
* @property isSelfHost If the organization is self hosted.
* @property permissions The permissions of the organization.
* @property providerId The provider ID of the organization (nullable).
* @property id The ID of the organization.
* @property shouldUseGroups If the organization should use groups.
* @property shouldUseDirectory If the organization should use a directory.
* @property key The key of the organization (nullable).
* @property providerName The provider name of the organization (nullable).
* @property shouldUsersGetPremium If users of the organization get premium.
* @property maxStorageGb The max storage in Gb of the organization (nullable).
* @property identifier The identifier of the organization (nullable).
* @property use2fa If the organization uses 2FA.
* @property familySponsorshipToDelete If the organization has a
* family sponsorship to delete (nullable).
* @property userId The user id (nullable).
* @property shouldUseEvents If the organization should use events.
* @property familySponsorshipFriendlyName If the family sponsorship is a friendly name.
* @property shouldUseTotp If he organization should use TOTP.
* @property familySponsorshipLastSyncDate The last date the family sponsorship
* was synced (nullable).
* @property name The name of the organization (nullable).
* @property shouldUseApi If the organization should use API.
* @property familySponsorshipValidUntil The family sponsorship valid until
* of the organization (nullable).
* @property status The status of the organization.
*/
@Serializable
data class Organization(
@SerialName("usePolicies")
val shouldUsePolicies: Boolean,
@SerialName("keyConnectorEnabled")
val shouldUseKeyConnector: Boolean,
@SerialName("keyConnectorUrl")
val keyConnectorUrl: String?,
@SerialName("type")
val type: OrganizationType,
@SerialName("seats")
val seats: Int?,
@SerialName("enabled")
val isEnabled: Boolean,
@SerialName("providerType")
val providerType: Int?,
@SerialName("maxCollections")
val maxCollections: Int?,
@SerialName("selfHost")
val isSelfHost: Boolean,
@SerialName("permissions")
val permissions: Permissions,
@SerialName("providerId")
val providerId: String?,
@SerialName("id")
val id: String,
@SerialName("useGroups")
val shouldUseGroups: Boolean,
@SerialName("useDirectory")
val shouldUseDirectory: Boolean,
@SerialName("key")
val key: String?,
@SerialName("providerName")
val providerName: String?,
@SerialName("usersGetPremium")
val shouldUsersGetPremium: Boolean,
@SerialName("maxStorageGb")
val maxStorageGb: Int?,
@SerialName("identifier")
val identifier: String?,
@SerialName("use2fa")
val use2fa: Boolean,
@SerialName("familySponsorshipToDelete")
val familySponsorshipToDelete: Boolean?,
@SerialName("userId")
val userId: String?,
@SerialName("useEvents")
val shouldUseEvents: Boolean,
@SerialName("familySponsorshipFriendlyName")
val familySponsorshipFriendlyName: String?,
@SerialName("useTotp")
val shouldUseTotp: Boolean,
@SerialName("familySponsorshipLastSyncDate")
@Contextual
val familySponsorshipLastSyncDate: ZonedDateTime?,
@SerialName("name")
val name: String?,
@SerialName("useApi")
val shouldUseApi: Boolean,
@SerialName("familySponsorshipValidUntil")
@Contextual
val familySponsorshipValidUntil: ZonedDateTime?,
@SerialName("status")
val status: OrganizationStatusType,
)
/**
* Represents a provider in the vault response.
*
* @property shouldUseEvents If the provider should use events.
* @property permissions The permissions of the provider.
* @property name The name of the provider (nullable).
* @property id The ID of the provider.
* @property type The type of provider.
* @property userId The user ID of the provider (nullable).
* @property key The key of the provider (nullable).
* @property isEnabled If the provider is enabled.
* @property status The status of the provider.
*/
@Serializable
data class Provider(
@SerialName("useEvents")
val shouldUseEvents: Boolean,
@SerialName("permissions")
val permissions: Permissions,
@SerialName("name")
val name: String?,
@SerialName("id")
val id: String,
@SerialName("type")
val type: Int,
@SerialName("userId")
val userId: String?,
@SerialName("key")
val key: String?,
@SerialName("enabled")
val isEnabled: Boolean,
@SerialName("status")
val status: Int,
)
/**
* Represents permissions in the vault response.
*
* @property shouldManageResetPassword If reset password should be managed.
* @property shouldManagePolicies If policies should be managed.
*/
@Serializable
data class Permissions(
@SerialName("manageResetPassword")
val shouldManageResetPassword: Boolean,
@SerialName("managePolicies")
val shouldManagePolicies: Boolean,
)
}
/**
* Represents a cipher in the vault response.
*
* @property notes The notes of the cipher (nullable).
* @property attachments A list of attachments associated with the cipher (nullable).
* @property shouldOrganizationUseTotp If organizations use TOTP for the cipher.
* @property reprompt The reprompt of the cipher.
* @property shouldEdit If the cipher can edit.
* @property passwordHistory A list of password history objects
* associated with the cipher (nullable).
* @property revisionDate The revision date of the cipher.
* @property type The type of cipher.
* @property login The login of the cipher.
* @property creationDate The creation date of the cipher.
* @property secureNote The secure note of the cipher.
* @property folderId The folder ID of the cipher (nullable).
* @property organizationId The organization ID of the cipher (nullable).
* @property deletedDate The deleted date of the cipher (nullable).
* @property identity The identity of the cipher.
* @property collectionIds A list of collection IDs associated with the cipher (nullable).
* @property name The name of the cipher (nullable).
* @property id The ID of the cipher.
* @property fields A list of fields associated with the cipher (nullable).
* @property shouldViewPassword If the password can be viewed for the cipher.
* @property isFavorite If the cipher is a favorite.
* @property card The card of the cipher.
*/
@Serializable
data class Cipher(
@SerialName("notes")
val notes: String?,
@SerialName("attachments")
val attachments: List<Attachment>?,
@SerialName("organizationUseTotp")
val shouldOrganizationUseTotp: Boolean,
@SerialName("reprompt")
val reprompt: CipherRepromptTypeJson,
@SerialName("edit")
val shouldEdit: Boolean,
@SerialName("passwordHistory")
val passwordHistory: List<PasswordHistory>?,
@SerialName("revisionDate")
@Contextual
val revisionDate: ZonedDateTime,
@SerialName("type")
val type: CipherTypeJson,
@SerialName("login")
val login: Login?,
@SerialName("creationDate")
@Contextual
val creationDate: ZonedDateTime,
@SerialName("secureNote")
val secureNote: SecureNote?,
@SerialName("folderId")
val folderId: String?,
@SerialName("organizationId")
val organizationId: String?,
@SerialName("deletedDate")
@Contextual
val deletedDate: ZonedDateTime?,
@SerialName("identity")
val identity: Identity?,
@SerialName("sshKey")
val sshKey: SshKey?,
@SerialName("collectionIds")
val collectionIds: List<String>?,
@SerialName("name")
val name: String?,
@SerialName("id")
val id: String,
@SerialName("fields")
val fields: List<Field>?,
@SerialName("viewPassword")
val shouldViewPassword: Boolean,
@SerialName("favorite")
val isFavorite: Boolean,
@SerialName("card")
val card: Card?,
@SerialName("key")
val key: String?,
) {
/**
* Represents an attachment in the vault response.
*
* @property fileName The file name of the attachment (nullable).
* @property size The size of the attachment (nullable).
* @property sizeName The size name of the attachment (nullable).
* @property id The ID of the attachment (nullable).
* @property url The URL of the attachment (nullable).
* @property key The key of the attachment (nullable).
*/
@Serializable
data class Attachment(
@SerialName("fileName")
val fileName: String?,
@SerialName("size")
val size: Int,
@SerialName("sizeName")
val sizeName: String?,
@SerialName("id")
val id: String?,
@SerialName("url")
val url: String?,
@SerialName("key")
val key: String?,
)
/**
* Represents a card in the vault response.
*
* @property number The number of the card (nullable).
* @property expMonth The expiration month of the card (nullable).
* @property code The code of the card (nullable).
* @property expirationYear The expiration year of the card (nullable).
* @property cardholderName The name of the card holder (nullable).
* @property brand The brand of the card (nullable).
*/
@Serializable
data class Card(
@SerialName("number")
val number: String?,
@SerialName("expMonth")
val expMonth: String?,
@SerialName("code")
val code: String?,
@SerialName("expYear")
val expirationYear: String?,
@SerialName("cardholderName")
val cardholderName: String?,
@SerialName("brand")
val brand: String?,
)
/**
* Represents a field in the vault response.
*
* @property linkedIdType The linked ID of the field (nullable).
* @property name The name of the field (nullable).
* @property type The type of field.
* @property value The value of the field (nullable).
*/
@Serializable
data class Field(
@SerialName("linkedId")
val linkedIdType: LinkedIdTypeJson?,
@SerialName("name")
val name: String?,
@SerialName("type")
val type: FieldTypeJson,
@SerialName("value")
val value: String?,
)
/**
* Represents an identity in the vault response.
*
* @property passportNumber The passport number of the identity (nullable).
* @property lastName The last name of the identity (nullable).
* @property country The country of the identity (nullable).
* @property address3 The third address of the identity (nullable).
* @property address2 The second address of the identity (nullable).
* @property city The city of the identity (nullable).
* @property address1 The first address of the identity (nullable).
* @property postalCode The postal code of the identity (nullable).
* @property title The title of the identity (nullable).
* @property ssn The social security number of the identity (nullable).
* @property firstName The first name of the identity (nullable).
* @property phone The phone of the identity (nullable).
* @property middleName The middle name of the identity (nullable).
* @property company The company of the identity (nullable).
* @property licenseNumber The license number of the identity (nullable).
* @property state The state of the identity (nullable).
* @property email The email of the identity (nullable).
* @property username The username of the identity (nullable).
*/
@Serializable
data class Identity(
@SerialName("passportNumber")
val passportNumber: String?,
@SerialName("lastName")
val lastName: String?,
@SerialName("country")
val country: String?,
@SerialName("address3")
val address3: String?,
@SerialName("address2")
val address2: String?,
@SerialName("city")
val city: String?,
@SerialName("address1")
val address1: String?,
@SerialName("postalCode")
val postalCode: String?,
@SerialName("title")
val title: String?,
@SerialName("ssn")
val ssn: String?,
@SerialName("firstName")
val firstName: String?,
@SerialName("phone")
val phone: String?,
@SerialName("middleName")
val middleName: String?,
@SerialName("company")
val company: String?,
@SerialName("licenseNumber")
val licenseNumber: String?,
@SerialName("state")
val state: String?,
@SerialName("email")
val email: String?,
@SerialName("username")
val username: String?,
)
/**
* Represents a login object in the vault response.
*
* @property uris A list of URIs (nullable).
* @property totp The TOTP (nullable).
* @property password The password (nullable).
* @property passwordRevisionDate The password revision date (nullable).
* @property shouldAutofillOnPageLoad If autofill is used on page load (nullable).
* @property uri The URI (nullable).
* @property username The username (nullable).
* @property fido2Credentials A list of FIDO 2 credentials (nullable).
*/
@Serializable
data class Login(
@SerialName("uris")
val uris: List<Uri>?,
@SerialName("totp")
val totp: String?,
@SerialName("password")
val password: String?,
@SerialName("passwordRevisionDate")
@Contextual
val passwordRevisionDate: ZonedDateTime?,
@SerialName("autofillOnPageLoad")
val shouldAutofillOnPageLoad: Boolean?,
@SerialName("uri")
val uri: String?,
@SerialName("username")
val username: String?,
@SerialName("fido2Credentials")
val fido2Credentials: List<Fido2Credential>?,
) {
/**
* Represents a URI in the vault response.
*
* @property uriMatchType The match type of the URI.
* @property uri The actual string representing the URI (nullable).
*/
@Serializable
data class Uri(
@SerialName("match")
val uriMatchType: UriMatchTypeJson?,
@SerialName("uri")
val uri: String?,
@SerialName("uriChecksum")
val uriChecksum: String?,
)
}
/**
* Represents a SSH key in the vault response.
*
* @property publicKey The public key of the SSH key.
* @property privateKey The private key of the SSH key.
* @property keyFingerprint The key fingerprint of the SSH key.
*/
@Serializable
data class SshKey(
@SerialName("publicKey")
val publicKey: String,
@SerialName("privateKey")
val privateKey: String,
@SerialName("keyFingerprint")
val keyFingerprint: String,
)
/**
* Represents password history in the vault response.
*
* @property password The password of the password history object.
* @property lastUsedDate The last used date of the password history object.
*/
@Serializable
data class PasswordHistory(
@SerialName("password")
val password: String,
@SerialName("lastUsedDate")
@Contextual
val lastUsedDate: ZonedDateTime,
)
/**
* Represents a secure note in the vault response.
*
* @property type The type of secure note.
*/
@Serializable
data class SecureNote(
@SerialName("type")
val type: SecureNoteTypeJson,
)
/**
* Represents a FIDO2 credential object in the vault response.
*
* @property credentialId The unique identifier of the FIDO2 credential.
* @property keyType The type of public key of the FIDO2 credential.
* @property keyAlgorithm The public Key algorithm of the credential.
* @property keyValue The public key of the credential.
* @property rpId The relying party (RP) identity.
* @property rpName The optional name of the relying party (RP).
* @property userHandle The optional unique identifier used to identify an account.
* @property userName The conditional, formal name of the user associated to the credential.
* @property userDisplayName The optional display name of the user associated to the
* credential.
* @property counter The signature counter for the credential.
* @property discoverable Whether the FIDO2 credential is discoverable or non-discoverable.
* @property creationDate The creation date and time of the credential.
*/
@Serializable
data class Fido2Credential(
@SerialName("credentialId")
val credentialId: String,
@SerialName("keyType")
val keyType: String = DEFAULT_FIDO_2_KEY_TYPE,
@SerialName("keyAlgorithm")
val keyAlgorithm: String = DEFAULT_FIDO_2_KEY_ALGORITHM,
@SerialName("keyCurve")
val keyCurve: String = DEFAULT_FIDO_2_KEY_CURVE,
@SerialName("keyValue")
val keyValue: String,
@SerialName("rpId")
val rpId: String,
@SerialName("rpName")
val rpName: String?,
@SerialName("userHandle")
val userHandle: String?,
@SerialName("userName")
val userName: String?,
@SerialName("userDisplayName")
val userDisplayName: String?,
@SerialName("counter")
val counter: String,
@SerialName("discoverable")
val discoverable: String,
@SerialName("creationDate")
@Contextual
val creationDate: ZonedDateTime,
)
}
/**
* Represents a send object in the vault response.
*
* @property accessCount The access count of the send object.
* @property notes The notes of the send object (nullable).
* @property revisionDate The revision date of the send object.
* @property maxAccessCount The max access count of the send object (nullable).
* @property shouldHideEmail If the send object should hide the email.
* @property type The type of send object.
* @property accessId The access ID of the send object (nullable).
* @property password The password of the send object (nullable).
* @property file The file of the send object.
* @property deletionDate The max access count of the send object.
* @property name The name of the send object (nullable).
* @property isDisabled If the send object is disabled.
* @property id The ID the send object.
* @property text The text of the send object.
* @property key The key of the send object (nullable).
* @property expirationDate The expiration date of the send object (nullable).
*/
@Serializable
data class Send(
@SerialName("accessCount")
val accessCount: Int,
@SerialName("notes")
val notes: String?,
@SerialName("revisionDate")
@Contextual
val revisionDate: ZonedDateTime,
@SerialName("maxAccessCount")
val maxAccessCount: Int?,
@SerialName("hideEmail")
val shouldHideEmail: Boolean,
@SerialName("type")
val type: SendTypeJson,
@SerialName("accessId")
val accessId: String?,
@SerialName("password")
val password: String?,
@SerialName("file")
val file: File?,
@SerialName("deletionDate")
@Contextual
val deletionDate: ZonedDateTime,
@SerialName("name")
val name: String?,
@SerialName("disabled")
val isDisabled: Boolean,
@SerialName("id")
val id: String,
@SerialName("text")
val text: Text?,
@SerialName("key")
val key: String?,
@SerialName("expirationDate")
@Contextual
val expirationDate: ZonedDateTime?,
) {
/**
* Represents a file in the vault response.
*
* @property fileName The name of the file (nullable).
* @property size The size of the file (nullable).
* @property sizeName The size name of the file (nullable).
* @property id The ID of the file (nullable).
*/
@Serializable
data class File(
@SerialName("fileName")
val fileName: String?,
@SerialName("size")
val size: Int?,
@SerialName("sizeName")
val sizeName: String?,
@SerialName("id")
val id: String?,
)
/**
* Represents text in the vault response.
*
* @property isHidden If the text is hidden or not.
* @property text The actual string representing the text (nullable).
*/
@Serializable
data class Text(
@SerialName("hidden")
val isHidden: Boolean,
@SerialName("text")
val text: String?,
)
}
/**
* Represents a collection in the vault response.
*
* @property organizationId The organization ID of the collection.
* @property shouldHidePasswords If the collection should hide passwords.
* @property name The name of the collection.
* @property externalId The external ID of the collection (nullable).
* @property isReadOnly If the collection is marked as read only.
* @property id The ID of the collection.
*/
@Serializable
data class Collection(
@SerialName("organizationId")
val organizationId: String,
@SerialName("hidePasswords")
val shouldHidePasswords: Boolean,
@SerialName("name")
val name: String,
@SerialName("externalId")
val externalId: String?,
@SerialName("readOnly")
val isReadOnly: Boolean,
@SerialName("id")
val id: String,
@SerialName("manage")
val canManage: Boolean?,
)
}

View File

@@ -0,0 +1,15 @@
package com.bitwarden.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents an update cipher collections request.
*
* @property collectionIds A list of collection ids associated with the cipher.
*/
@Serializable
data class UpdateCipherCollectionsJsonRequest(
@SerialName("CollectionIds")
val collectionIds: List<String>,
)

View File

@@ -0,0 +1,54 @@
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 how a URI should be matched for autofill to occur.
*/
@Serializable(UriMatchTypeSerializer::class)
enum class UriMatchTypeJson {
/**
* Matching of the URI is based on the domain.
*/
@SerialName("0")
DOMAIN,
/**
* Matching of the URI is based on the host.
*/
@SerialName("1")
HOST,
/**
* Matching of the URI is based the start of resource.
*/
@SerialName("2")
STARTS_WITH,
/**
* Matching of the URI requires an exact match.
*/
@SerialName("3")
EXACT,
/**
* Requires users to authenticate with SSO.
*/
@SerialName("4")
REGULAR_EXPRESSION,
/**
* The URI should never be autofilled.
*/
@SerialName("5")
NEVER,
}
@Keep
private class UriMatchTypeSerializer : BaseEnumeratedIntSerializer<UriMatchTypeJson>(
className = "UriMatchTypeJson",
values = UriMatchTypeJson.entries.toTypedArray(),
)

View File

@@ -0,0 +1,11 @@
package com.bitwarden.network.model
/**
* Create a mock [CipherJsonRequest] with a given [number].
*/
fun createMockAttachmentJsonRequest(number: Int): AttachmentJsonRequest =
AttachmentJsonRequest(
fileName = "mockFileName-$number",
key = "mockKey-$number",
fileSize = "1",
)

View File

@@ -0,0 +1,15 @@
package com.bitwarden.network.model
/**
* Create a mock [AttachmentJsonResponse] with a given [number].
*/
fun createMockAttachmentJsonResponse(
number: Int,
fileUploadType: FileUploadType = FileUploadType.AZURE,
): AttachmentJsonResponse =
AttachmentJsonResponse(
attachmentId = "mockAttachmentId-$number",
url = "mockUrl-$number",
fileUploadType = fileUploadType,
cipherResponse = createMockCipher(number = number),
)

View File

@@ -0,0 +1,33 @@
package com.bitwarden.network.model
import java.time.ZonedDateTime
/**
* Create a mock [CipherJsonRequest] with a given [number].
*/
fun createMockCipherJsonRequest(number: Int, hasNullUri: Boolean = false): CipherJsonRequest =
CipherJsonRequest(
attachments = mapOf(
"mockId-$number" to AttachmentJsonRequest(
fileName = "mockFileName-$number",
key = "mockKey-$number",
fileSize = "1",
),
),
organizationId = "mockOrganizationId-$number",
folderId = "mockFolderId-$number",
name = "mockName-$number",
notes = "mockNotes-$number",
type = CipherTypeJson.LOGIN,
login = createMockLogin(number = number, hasNullUri = hasNullUri),
card = createMockCard(number = number),
sshKey = createMockSshKey(number = number),
fields = listOf(createMockField(number = number)),
identity = createMockIdentity(number = number),
isFavorite = false,
passwordHistory = listOf(createMockPasswordHistory(number = number)),
reprompt = CipherRepromptTypeJson.NONE,
secureNote = createMockSecureNote(),
lastKnownRevisionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
key = "mockKey-$number",
)

View File

@@ -0,0 +1,26 @@
package com.bitwarden.network.model
import java.time.ZonedDateTime
/**
* Create a mock [SendJsonRequest] with a given [number].
*/
fun createMockSendJsonRequest(
number: Int,
type: SendTypeJson = SendTypeJson.FILE,
): SendJsonRequest =
SendJsonRequest(
name = "mockName-$number",
notes = "mockNotes-$number",
type = type,
key = "mockKey-$number",
maxAccessCount = 1,
expirationDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
deletionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
fileLength = 1,
file = createMockFile(number),
text = createMockText(number),
password = "mockPassword-$number",
isDisabled = false,
shouldHideEmail = false,
)

View File

@@ -0,0 +1,188 @@
package com.bitwarden.network.model
import java.time.ZonedDateTime
/**
* Constant date time used for [ZonedDateTime] properties of mock objects.
*/
private val MOCK_ZONED_DATE_TIME = ZonedDateTime.parse("2023-10-27T12:00:00Z")
/**
* Create a mock [SyncResponseJson.Cipher] with a given [number].
*/
fun createMockCipher(
number: Int,
hasNullUri: Boolean = false,
fido2Credentials: List<SyncResponseJson.Cipher.Fido2Credential> = listOf(
createMockFido2Credential(number),
),
isDeleted: Boolean = true,
): SyncResponseJson.Cipher =
SyncResponseJson.Cipher(
id = "mockId-$number",
organizationId = "mockOrganizationId-$number",
folderId = "mockFolderId-$number",
collectionIds = listOf("mockCollectionId-$number"),
name = "mockName-$number",
notes = "mockNotes-$number",
type = CipherTypeJson.LOGIN,
login = createMockLogin(
number = number,
hasNullUri = hasNullUri,
fido2Credentials = fido2Credentials,
),
creationDate = MOCK_ZONED_DATE_TIME,
deletedDate = if (isDeleted) MOCK_ZONED_DATE_TIME else null,
revisionDate = MOCK_ZONED_DATE_TIME,
attachments = listOf(createMockAttachment(number = number)),
card = createMockCard(number = number),
fields = listOf(createMockField(number = number)),
identity = createMockIdentity(number = number),
sshKey = createMockSshKey(number = number),
isFavorite = false,
passwordHistory = listOf(createMockPasswordHistory(number = number)),
reprompt = CipherRepromptTypeJson.NONE,
secureNote = createMockSecureNote(),
shouldEdit = false,
shouldOrganizationUseTotp = false,
shouldViewPassword = false,
key = "mockKey-$number",
)
/**
* Create a mock [SyncResponseJson.Cipher.Identity] with a given [number].
*/
fun createMockIdentity(number: Int): SyncResponseJson.Cipher.Identity =
SyncResponseJson.Cipher.Identity(
firstName = "mockFirstName-$number",
middleName = "mockMiddleName-$number",
lastName = "mockLastName-$number",
passportNumber = "mockPassportNumber-$number",
country = "mockCountry-$number",
address1 = "mockAddress1-$number",
address2 = "mockAddress2-$number",
address3 = "mockAddress3-$number",
city = "mockCity-$number",
postalCode = "mockPostalCode-$number",
title = "mockTitle-$number",
ssn = "mockSsn-$number",
phone = "mockPhone-$number",
company = "mockCompany-$number",
licenseNumber = "mockLicenseNumber-$number",
state = "mockState-$number",
email = "mockEmail-$number",
username = "mockUsername-$number",
)
/**
* Create a mock [SyncResponseJson.Cipher.Attachment] with a given [number].
*/
fun createMockAttachment(number: Int): SyncResponseJson.Cipher.Attachment =
SyncResponseJson.Cipher.Attachment(
fileName = "mockFileName-$number",
size = 1,
sizeName = "mockSizeName-$number",
id = "mockId-$number",
url = "mockUrl-$number",
key = "mockKey-$number",
)
/**
* Create a mock [SyncResponseJson.Cipher.Card] with a given [number].
*/
fun createMockCard(number: Int): SyncResponseJson.Cipher.Card =
SyncResponseJson.Cipher.Card(
number = "mockNumber-$number",
expMonth = "mockExpMonth-$number",
code = "mockCode-$number",
expirationYear = "mockExpirationYear-$number",
cardholderName = "mockCardholderName-$number",
brand = "mockBrand-$number",
)
/**
* Create a mock [SyncResponseJson.Cipher.PasswordHistory] with a given [number].
*/
fun createMockPasswordHistory(number: Int): SyncResponseJson.Cipher.PasswordHistory =
SyncResponseJson.Cipher.PasswordHistory(
password = "mockPassword-$number",
lastUsedDate = MOCK_ZONED_DATE_TIME,
)
/**
* Create a mock [SyncResponseJson.Cipher.SecureNote].
*/
fun createMockSecureNote(): SyncResponseJson.Cipher.SecureNote =
SyncResponseJson.Cipher.SecureNote(
type = SecureNoteTypeJson.GENERIC,
)
/**
* Create a mock [SyncResponseJson.Cipher.Field] with a given [number].
*/
fun createMockField(number: Int): SyncResponseJson.Cipher.Field =
SyncResponseJson.Cipher.Field(
linkedIdType = LinkedIdTypeJson.LOGIN_USERNAME,
name = "mockName-$number",
type = FieldTypeJson.HIDDEN,
value = "mockValue-$number",
)
/**
* Create a mock [SyncResponseJson.Cipher.Login] with a given [number].
*/
fun createMockLogin(
number: Int,
hasNullUri: Boolean = false,
fido2Credentials: List<SyncResponseJson.Cipher.Fido2Credential> = listOf(
createMockFido2Credential(number),
),
): SyncResponseJson.Cipher.Login =
SyncResponseJson.Cipher.Login(
username = "mockUsername-$number",
password = "mockPassword-$number",
passwordRevisionDate = MOCK_ZONED_DATE_TIME,
shouldAutofillOnPageLoad = false,
uri = if (hasNullUri) null else "mockUri-$number",
uris = listOf(createMockUri(number = number)),
totp = "mockTotp-$number",
fido2Credentials = fido2Credentials,
)
/**
* Create a mock [SyncResponseJson.Cipher.SshKey] with a given [number].
*/
fun createMockSshKey(number: Int) = SyncResponseJson.Cipher.SshKey(
publicKey = "mockPublicKey-$number",
privateKey = "mockPrivateKey-$number",
keyFingerprint = "mockKeyFingerprint-$number",
)
/**
* Create a mock [SyncResponseJson.Cipher.Fido2Credential] with a given [number].
*/
fun createMockFido2Credential(number: Int) = SyncResponseJson.Cipher.Fido2Credential(
credentialId = "mockCredentialId-$number",
keyType = "mockKeyType-$number",
keyAlgorithm = "mockKeyAlgorithm-$number",
keyCurve = "mockKeyCurve-$number",
keyValue = "mockKeyValue-$number",
rpId = "mockRpId-$number",
rpName = "mockRpName-$number",
userHandle = "mockUserHandle-$number",
userName = "mockUserName-$number",
userDisplayName = "mockUserDisplayName-$number",
counter = "mockCounter-$number",
discoverable = "mockDiscoverable-$number",
creationDate = MOCK_ZONED_DATE_TIME,
)
/**
* Create a mock [SyncResponseJson.Cipher.Login.Uri] with a given [number].
*/
fun createMockUri(number: Int): SyncResponseJson.Cipher.Login.Uri =
SyncResponseJson.Cipher.Login.Uri(
uri = "mockUri-$number",
uriMatchType = UriMatchTypeJson.HOST,
uriChecksum = "mockUriChecksum-$number",
)

View File

@@ -0,0 +1,15 @@
package com.bitwarden.network.model
/**
* Create a mock [SyncResponseJson.Collection] with a given [number].
*/
fun createMockCollection(number: Int): SyncResponseJson.Collection =
SyncResponseJson.Collection(
organizationId = "mockOrganizationId-$number",
shouldHidePasswords = false,
name = "mockName-$number",
externalId = "mockExternalId-$number",
isReadOnly = false,
id = "mockId-$number",
canManage = true,
)

View File

@@ -0,0 +1,22 @@
package com.bitwarden.network.model
/**
* Create a mock [SyncResponseJson.Domains] with a given [number].
*/
fun createMockDomains(number: Int): SyncResponseJson.Domains =
SyncResponseJson.Domains(
globalEquivalentDomains = listOf(
SyncResponseJson.Domains.GlobalEquivalentDomain(
isExcluded = false,
domains = listOf(
"mockDomain-$number",
),
type = 1,
),
),
equivalentDomains = listOf(
listOf(
"mockEquivalentDomain-$number",
),
),
)

View File

@@ -0,0 +1,13 @@
package com.bitwarden.network.model
import java.time.ZonedDateTime
/**
* Create a mock [SyncResponseJson.Folder] with a given [number].
*/
fun createMockFolder(number: Int): SyncResponseJson.Folder =
SyncResponseJson.Folder(
id = "mockId-$number",
name = "mockName-$number",
revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
)

View File

@@ -0,0 +1,21 @@
package com.bitwarden.network.model
import kotlinx.serialization.json.JsonObject
/**
* Create a mock [SyncResponseJson.Policy] with the given [number], [type], and [data].
*/
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 = organizationId,
id = "mockId-$number",
type = type,
isEnabled = isEnabled,
data = data,
)

View File

@@ -0,0 +1,106 @@
package com.bitwarden.network.model
import java.time.ZonedDateTime
/**
* Create a mock [SyncResponseJson.Profile] with a given [number].
*/
fun createMockProfile(number: Int): SyncResponseJson.Profile =
SyncResponseJson.Profile(
providerOrganizations = listOf(createMockOrganization(number = number)),
isPremiumFromOrganization = false,
shouldForcePasswordReset = false,
avatarColor = "mockAvatarColor-$number",
isEmailVerified = false,
isTwoFactorEnabled = false,
privateKey = "mockPrivateKey-$number",
isPremium = false,
culture = "mockCulture-$number",
name = "mockName-$number",
organizations = listOf(createMockOrganization(number = number)),
shouldUseKeyConnector = false,
id = "mockId-$number",
masterPasswordHint = "mockMasterPasswordHint-$number",
email = "mockEmail-$number",
key = "mockKey-$number",
securityStamp = "mockSecurityStamp-$number",
providers = listOf(createMockProvider(number = number)),
creationDate = ZonedDateTime.parse("2024-09-13T01:00:00.00Z"),
)
/**
* Create a mock [SyncResponseJson.Profile.Organization] with a given [number].
*/
fun createMockOrganization(
number: Int,
isEnabled: Boolean = false,
shouldUsePolicies: Boolean = false,
shouldManageResetPassword: Boolean = false,
type: OrganizationType = OrganizationType.ADMIN,
): SyncResponseJson.Profile.Organization =
SyncResponseJson.Profile.Organization(
shouldUsePolicies = shouldUsePolicies,
shouldUseKeyConnector = false,
keyConnectorUrl = "mockKeyConnectorUrl-$number",
type = type,
seats = 1,
isEnabled = isEnabled,
providerType = 1,
maxCollections = 1,
isSelfHost = false,
permissions = createMockPermissions(shouldManageResetPassword = shouldManageResetPassword),
providerId = "mockProviderId-$number",
id = "mockId-$number",
shouldUseGroups = false,
shouldUseDirectory = false,
key = "mockKey-$number",
providerName = "mockProviderName-$number",
shouldUsersGetPremium = false,
maxStorageGb = 1,
identifier = "mockIdentifier-$number",
use2fa = false,
familySponsorshipToDelete = false,
userId = "mockUserId-$number",
shouldUseEvents = false,
familySponsorshipFriendlyName = "mockFamilySponsorshipFriendlyName-$number",
shouldUseTotp = false,
familySponsorshipLastSyncDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
name = "mockName-$number",
shouldUseApi = false,
familySponsorshipValidUntil = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
status = OrganizationStatusType.ACCEPTED,
)
/**
* Create a mock set of organization keys with the given [number].
*/
fun createMockOrganizationKeys(number: Int): Map<String, String> =
createMockOrganization(number = number)
.let { mapOf(it.id to requireNotNull(it.key)) }
/**
* Create a mock [SyncResponseJson.Profile.Permissions].
*/
fun createMockPermissions(
shouldManageResetPassword: Boolean = false,
): SyncResponseJson.Profile.Permissions =
SyncResponseJson.Profile.Permissions(
shouldManageResetPassword = shouldManageResetPassword,
shouldManagePolicies = false,
)
/**
* Create a mock [SyncResponseJson.Profile.Provider] with a given [number].
*/
fun createMockProvider(number: Int): SyncResponseJson.Profile.Provider =
SyncResponseJson.Profile.Provider(
shouldUseEvents = false,
permissions = createMockPermissions(),
name = "mockName-$number",
id = "mockId-$number",
type = 1,
userId = "mockUserId-$number",
key = "mockKey-$number",
isEnabled = false,
status = 1,
)

View File

@@ -0,0 +1,47 @@
package com.bitwarden.network.model
import java.time.ZonedDateTime
fun createMockFileSendResponseJson(number: Int, type: SendTypeJson = SendTypeJson.FILE) =
CreateFileSendResponseJson(
url = "www.test.com",
fileUploadType = FileUploadType.AZURE,
sendResponse = createMockSend(number = number, type = type),
)
fun createMockSend(
number: Int,
type: SendTypeJson = SendTypeJson.FILE,
): SyncResponseJson.Send =
SyncResponseJson.Send(
accessCount = 1,
notes = "mockNotes-$number",
revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
maxAccessCount = 1,
shouldHideEmail = false,
type = type,
accessId = "mockAccessId-$number",
password = "mockPassword-$number",
file = createMockFile(number = number),
deletionDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
name = "mockName-$number",
isDisabled = false,
id = "mockId-$number",
text = createMockText(number = number),
key = "mockKey-$number",
expirationDate = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
)
fun createMockFile(number: Int): SyncResponseJson.Send.File =
SyncResponseJson.Send.File(
fileName = "mockFileName-$number",
size = 1,
sizeName = "mockSizeName-$number",
id = "mockId-$number",
)
fun createMockText(number: Int): SyncResponseJson.Send.Text =
SyncResponseJson.Send.Text(
isHidden = false,
text = "mockText-$number",
)

View File

@@ -0,0 +1,12 @@
package com.bitwarden.network.model
fun createMockSyncResponse(number: Int): SyncResponseJson =
SyncResponseJson(
folders = listOf(createMockFolder(number = number)),
collections = listOf(createMockCollection(number = number)),
profile = createMockProfile(number = number),
ciphers = listOf(createMockCipher(number = number)),
policies = listOf(createMockPolicy(number = number)),
domains = createMockDomains(number = number),
sends = listOf(createMockSend(number = number)),
)