This commit is contained in:
Matt Gibson 2024-10-22 13:31:23 -07:00
parent 89dceb2485
commit 810fd2f428
No known key found for this signature in database
GPG key ID: 7CBCA182C13B0912
5 changed files with 123 additions and 925 deletions

View file

@ -1,7 +1,6 @@
package com.x8bit.bitwarden.data.vault.datasource.disk
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.CipherView
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CiphersDao
@ -18,6 +17,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.entity.OfflineCipherEntity
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.repository.util.toOfflineCipher
import com.x8bit.bitwarden.data.vault.repository.util.toOfflineCipherJson
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
@ -59,7 +59,7 @@ class VaultDiskSourceImpl(
id = cipher.id ?: "create_${UUID.randomUUID()}",
userId = userId,
cipherType = json.encodeToString(cipher.type),
cipherJson = json.encodeToString(cipher.toOfflineCipher()),
cipherJson = json.encodeToString(cipher.toOfflineCipher().toOfflineCipherJson()),
),
),
)

View file

@ -70,7 +70,7 @@ data class OfflineCipherJson(
@SerialName("creationDate")
@Contextual
val creationDate: ZonedDateTime?,
val creationDate: ZonedDateTime,
@SerialName("deletionDate")
@Contextual
@ -78,915 +78,15 @@ data class OfflineCipherJson(
@SerialName("revisionDate")
@Contextual
val revisionDate: ZonedDateTime?,
val revisionDate: ZonedDateTime,
@SerialName("type")
@Contextual
val type: CipherTypeJson,
) {
/**
* 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("mergeConflict")
val mergeConflict: Boolean
@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).
*/
@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>?,
) {
/**
* 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("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 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,
)
){
// TODO: Add password history, fields, etc
}

View file

@ -0,0 +1,55 @@
package com.x8bit.bitwarden.data.vault.datasource.sdk.model
import com.bitwarden.core.DateTime
import com.bitwarden.core.Uuid
import com.bitwarden.crypto.EncString
import com.bitwarden.vault.Attachment
import com.bitwarden.vault.Card
import com.bitwarden.vault.CipherRepromptType
import com.bitwarden.vault.CipherType
import com.bitwarden.vault.Field
import com.bitwarden.vault.Identity
import com.bitwarden.vault.LocalData
import com.bitwarden.vault.Login
import com.bitwarden.vault.PasswordHistory
import com.bitwarden.vault.SecureNote
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherRepromptTypeJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherTypeJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.time.ZonedDateTime
/**
* Represents a vault item that has failed to be uploaded and must be stored locally
*
*
*/
data class OfflineCipher (
val id: Uuid?,
val organizationId: Uuid?,
val folderId: Uuid?,
val collectionIds: List<Uuid>,
/**
* More recent ciphers uses individual encryption keys to encrypt the other fields of the
* Cipher.
*/
val key: EncString?,
val name: EncString,
val notes: EncString?,
val type: CipherType,
val login: Login?,
val identity: Identity?,
val card: Card?,
val secureNote: SecureNote?,
val favorite: kotlin.Boolean,
val reprompt: CipherRepromptType,
val attachments: List<Attachment>?,
val fields: List<Field>?,
val passwordHistory: List<PasswordHistory>?,
val creationDate: DateTime,
val deletedDate: DateTime?,
val revisionDate: DateTime,
val mergeConflict: Boolean
)

View file

@ -30,6 +30,7 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.OfflineCipherJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.SecureNoteTypeJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.UriMatchTypeJson
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.OfflineCipher
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.util.UUID
@ -60,7 +61,32 @@ fun Cipher.toEncryptedNetworkCipher(): CipherJsonRequest =
key = key,
)
fun Cipher.toOfflineCipher(): OfflineCipherJson =
fun Cipher.toOfflineCipher(): OfflineCipher =
OfflineCipher (
id = id,
organizationId = organizationId,
folderId = folderId,
collectionIds = collectionIds,
key = key,
name = name,
notes = notes,
type = type,
login = login,
identity = identity,
card = card,
secureNote = secureNote,
favorite = favorite,
reprompt = reprompt,
attachments = attachments,
fields = fields,
passwordHistory = passwordHistory,
creationDate = creationDate,
deletedDate = deletedDate,
revisionDate = revisionDate,
mergeConflict = false,
)
fun OfflineCipher.toOfflineCipherJson(): OfflineCipherJson =
OfflineCipherJson(
id = id ?: "create_${UUID.randomUUID()}",
organizationId = organizationId,
@ -76,20 +102,17 @@ fun Cipher.toOfflineCipher(): OfflineCipherJson =
secureNote = secureNote?.toEncryptedNetworkSecureNote(),
favorite = favorite,
reprompt = reprompt.toNetworkRepromptType(),
// organizationUseTotp = shouldOrganizationUseTotp,
// edit = shouldEdit,
// viewPassword = shouldViewPassword,
// localData = null,
attachments = attachments?.toNetworkAttachmentList(),
fields = fields?.toEncryptedNetworkFieldList(),
passwordHistory = passwordHistory?.toEncryptedNetworkPasswordHistoryList(),
creationDate = creationDate?.let { ZonedDateTime.ofInstant(creationDate, ZoneOffset.UTC) },
creationDate = ZonedDateTime.ofInstant(creationDate, ZoneOffset.UTC),
deletedDate = deletedDate?.let { ZonedDateTime.ofInstant(deletedDate, ZoneOffset.UTC) },
revisionDate = revisionDate?.let { ZonedDateTime.ofInstant(creationDate, ZoneOffset.UTC) },
revisionDate = ZonedDateTime.ofInstant(creationDate, ZoneOffset.UTC),
mergeConflict = false, // TODO: Copy from the new OfflineCipher type
)
fun OfflineCipherJson.toCipher(): Cipher =
Cipher(
fun OfflineCipherJson.toOfflineCipher(): OfflineCipher =
OfflineCipher(
id = if(id.startsWith("create")) null else id,
organizationId = organizationId,
folderId = folderId,
@ -104,18 +127,38 @@ fun OfflineCipherJson.toCipher(): Cipher =
secureNote = secureNote?.toSdkSecureNote(),
favorite = favorite,
reprompt = reprompt.toSdkRepromptType(),
// Need to figure these out
organizationUseTotp = true,
edit = true,
viewPassword = true,
localData = null,
// ^^
attachments = attachments?.toSdkAttachmentList(),
fields = fields?.toSdkFieldList(),
passwordHistory = passwordHistory?.toSdkPasswordHistoryList(),
creationDate = creationDate?.toInstant() ?: DateTime.now(),
deletedDate = deletedDate?.toInstant(),
revisionDate = revisionDate?.toInstant() ?: DateTime.now(),
mergeConflict = mergeConflict
)
fun OfflineCipher.toCipher(): Cipher =
Cipher(
id = id,
organizationId = organizationId,
folderId = folderId,
collectionIds = collectionIds.orEmpty(),
key = key,
name = name.orEmpty(),
notes = notes,
type = type,
login = login,
identity = identity,
card = card,
secureNote = secureNote,
favorite = favorite,
reprompt = reprompt,
attachments = attachments,
fields = fields,
passwordHistory = passwordHistory,
creationDate = creationDate,
deletedDate = deletedDate,
revisionDate = revisionDate,
mergeConflict = mergeConflict
)
/**

View file

@ -1858,7 +1858,7 @@ class VaultAddEditViewModel @Inject constructor(
@Suppress("MaxLineLength")
private suspend fun VaultAddEditState.ViewState.Content.createCipherForAddAndCloneItemStates(): CreateCipherResult {
val result = common.selectedOwner?.collections
var result = common.selectedOwner?.collections
?.filter { it.isSelected }
?.map { it.id }
?.let {
@ -1871,7 +1871,7 @@ class VaultAddEditViewModel @Inject constructor(
if (result is CreateCipherResult.Error) {
// TODO: Ask for permission to store locally
vaultRepository.createOfflineCipher(cipherView = toCipherView())
result = vaultRepository.createOfflineCipher(cipherView = toCipherView())
}
return result;