diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/di/NetworkModule.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/di/NetworkModule.kt index 99d96abef..e145adfb9 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/di/NetworkModule.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/di/NetworkModule.kt @@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.platform.datasource.network.di import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import com.x8bit.bitwarden.data.platform.datasource.network.core.ResultCallAdapterFactory import com.x8bit.bitwarden.data.platform.datasource.network.interceptor.AuthTokenInterceptor +import com.x8bit.bitwarden.data.platform.datasource.network.serializer.LocalDateTimeSerializer import com.x8bit.bitwarden.data.platform.datasource.network.service.ConfigService import com.x8bit.bitwarden.data.platform.datasource.network.service.ConfigServiceImpl import dagger.Module @@ -11,11 +12,13 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.create +import java.time.LocalDateTime import javax.inject.Named import javax.inject.Singleton @@ -98,5 +101,8 @@ object NetworkModule { // We allow for nullable values to have keys missing in the JSON response. explicitNulls = false + serializersModule = SerializersModule { + contextual(LocalDateTime::class, LocalDateTimeSerializer()) + } } } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/serializer/LocalDateTimeSerializer.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/serializer/LocalDateTimeSerializer.kt new file mode 100644 index 000000000..a0cb57568 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/network/serializer/LocalDateTimeSerializer.kt @@ -0,0 +1,38 @@ +package com.x8bit.bitwarden.data.platform.datasource.network.serializer + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException + +/** + * Used to serialize and deserialize [LocalDateTime]. + */ +class LocalDateTimeSerializer : KSerializer { + private val localDateTimeFormatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SS'Z'") + private val localDateTimeFormatterNanoSeconds = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'") + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor(serialName = "LocalDateTime", kind = PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): LocalDateTime = + decoder.decodeString().let { dateString -> + try { + LocalDateTime + .parse(dateString, localDateTimeFormatter) + } catch (exception: DateTimeParseException) { + LocalDateTime + .parse(dateString, localDateTimeFormatterNanoSeconds) + } + } + + override fun serialize(encoder: Encoder, value: LocalDateTime) { + encoder.encodeString(localDateTimeFormatter.format(value)) + } +} diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CipherRepromptTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CipherRepromptTypeJson.kt new file mode 100644 index 000000000..5d7975c57 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CipherRepromptTypeJson.kt @@ -0,0 +1,26 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class CipherRepromptTypeSerializer : + BaseEnumeratedIntSerializer(CipherRepromptTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CipherTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CipherTypeJson.kt new file mode 100644 index 000000000..caf5c8002 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/CipherTypeJson.kt @@ -0,0 +1,38 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class CipherTypeSerializer : + BaseEnumeratedIntSerializer(CipherTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/FieldTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/FieldTypeJson.kt new file mode 100644 index 000000000..9c7a5ebad --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/FieldTypeJson.kt @@ -0,0 +1,38 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class FieldTypeSerializer : + BaseEnumeratedIntSerializer(FieldTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/LinkedIdTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/LinkedIdTypeJson.kt new file mode 100644 index 000000000..ad9b703e9 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/LinkedIdTypeJson.kt @@ -0,0 +1,182 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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 { + // region LOGIN + /** + * The field is linked to the login's username. + */ + @SerialName("100") + LOGIN_USERNAME, + + /** + * The field is linked to the login's password. + */ + @SerialName("101") + LOGIN_PASSWORD, + // endregion LOGIN + + // region CARD + /** + * The field is linked to the card's cardholder name. + */ + @SerialName("300") + CARD_CARDHOLDER_NAME, + + /** + * The field is linked to the card's expiration month. + */ + @SerialName("301") + CARD_EXP_MONTH, + + /** + * The field is linked to the card's expiration year. + */ + @SerialName("302") + CARD_EXP_YEAR, + + /** + * The field is linked to the card's code. + */ + @SerialName("303") + CARD_CODE, + + /** + * The field is linked to the card's brand. + */ + @SerialName("304") + CARD_BRAND, + + /** + * The field is linked to the card's number. + */ + @SerialName("305") + CARD_NUMBER, + // endregion CARD + + // region IDENTITY + /** + * The field is linked to the identity's title. + */ + @SerialName("400") + IDENTITY_TITLE, + + /** + * The field is linked to the identity's middle name. + */ + @SerialName("401") + IDENTITY_MIDDLE_NAME, + + /** + * The field is linked to the identity's address line 1. + */ + @SerialName("402") + IDENTITY_ADDRESS_1, + + /** + * The field is linked to the identity's address line 2. + */ + @SerialName("403") + IDENTITY_ADDRESS_2, + + /** + * The field is linked to the identity's address line 3. + */ + @SerialName("404") + IDENTITY_ADDRESS_3, + + /** + * The field is linked to the identity's city. + */ + @SerialName("405") + IDENTITY_CITY, + + /** + * The field is linked to the identity's state. + */ + @SerialName("406") + IDENTITY_STATE, + + /** + * The field is linked to the identity's postal code + */ + @SerialName("407") + IDENTITY_POSTAL_CODE, + + /** + * The field is linked to the identity's country. + */ + @SerialName("408") + IDENTITY_COUNTRY, + + /** + * The field is linked to the identity's company. + */ + @SerialName("409") + IDENTITY_COMPANY, + + /** + * The field is linked to the identity's email. + */ + @SerialName("410") + IDENTITY_EMAIL, + + /** + * The field is linked to the identity's phone. + */ + @SerialName("411") + IDENTITY_PHONE, + + /** + * The field is linked to the identity's SSN. + */ + @SerialName("412") + IDENTITY_SSN, + + /** + * The field is linked to the identity's username. + */ + @SerialName("413") + IDENTITY_USERNAME, + + /** + * The field is linked to the identity's passport number. + */ + @SerialName("414") + IDENTITY_PASSPORT_NUMBER, + + /** + * The field is linked to the identity's license number. + */ + @SerialName("415") + IDENTITY_LICENSE_NUMBER, + + /** + * The field is linked to the identity's first name. + */ + @SerialName("416") + IDENTITY_FIRST_NAME, + + /** + * The field is linked to the identity's last name. + */ + @SerialName("417") + IDENTITY_LAST_NAME, + + /** + * The field is linked to the identity's full name. + */ + @SerialName("418") + IDENTITY_FULL_NAME, + // endregion IDENTITY +} + +private class LinkedIdTypeSerializer : + BaseEnumeratedIntSerializer(LinkedIdTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/PolicyTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/PolicyTypeJson.kt new file mode 100644 index 000000000..16af8002f --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/PolicyTypeJson.kt @@ -0,0 +1,80 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class PolicyTypeSerializer : + BaseEnumeratedIntSerializer(PolicyTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SecureNoteTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SecureNoteTypeJson.kt new file mode 100644 index 000000000..5611e89b1 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SecureNoteTypeJson.kt @@ -0,0 +1,20 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class SecureNoteTypeSerializer : + BaseEnumeratedIntSerializer(SecureNoteTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SendTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SendTypeJson.kt new file mode 100644 index 000000000..a8bee8098 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SendTypeJson.kt @@ -0,0 +1,26 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class SendTypeSerializer : + BaseEnumeratedIntSerializer(SendTypeJson.values()) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseJson.kt index 234ff3f49..ea080f88b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseJson.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseJson.kt @@ -1,7 +1,9 @@ package com.x8bit.bitwarden.data.vault.datasource.network.model +import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import java.time.LocalDateTime /** * Represents the response model for vault data fetched from the server. @@ -14,7 +16,6 @@ import kotlinx.serialization.Serializable * @property domains A domains object associated with the vault data. * @property sends A list of send objects associated with the vault data (nullable). */ -// TODO determine encrypted params and rename them to emphasize encryption in BIT-636 @Serializable data class SyncResponseJson( @SerialName("folders") @@ -68,7 +69,6 @@ data class SyncResponseJson( @SerialName("domains") val domains: List?, - // TODO Parse type enum in BIT-636 @SerialName("type") val type: Int, ) @@ -83,9 +83,9 @@ data class SyncResponseJson( */ @Serializable data class Folder( - // TODO Serialize revision date in BIT-636 @SerialName("revisionDate") - val revisionDate: String?, + @Contextual + val revisionDate: LocalDateTime?, // Date @SerialName("name") val name: String?, @@ -110,9 +110,8 @@ data class SyncResponseJson( @SerialName("id") val id: String, - // TODO Parse type enum in BIT-636 @SerialName("type") - val type: Int, + val type: PolicyTypeJson, @SerialName("enabled") val isEnabled: Boolean, @@ -257,7 +256,7 @@ data class SyncResponseJson( @SerialName("keyConnectorUrl") val keyConnectorUrl: String?, - // TODO Parse type enum in BIT-636 + @SerialName("type") val type: Int, @@ -267,7 +266,6 @@ data class SyncResponseJson( @SerialName("enabled") val isEnabled: Boolean, - // TODO Parse provider type enum in BIT-636 @SerialName("providerType") val providerType: Int, @@ -331,7 +329,6 @@ data class SyncResponseJson( @SerialName("useResetPassword") val shouldUseResetPassword: Boolean, - // TODO Parse plan product type enum in BIT-636 @SerialName("planProductType") val planProductType: Int, @@ -362,9 +359,9 @@ data class SyncResponseJson( @SerialName("useTotp") val shouldUseTotp: Boolean, - // TODO Serialize family sponsorship last sync date in BIT-636 @SerialName("familySponsorshipLastSyncDate") - val familySponsorshipLastSyncDate: String?, + @Contextual + val familySponsorshipLastSyncDate: LocalDateTime?, @SerialName("useScim") val shouldUseScim: Boolean, @@ -412,7 +409,6 @@ data class SyncResponseJson( @SerialName("id") val id: String, - // TODO Parse type enum in BIT-636 @SerialName("type") val type: Int, @@ -532,7 +528,7 @@ data class SyncResponseJson( val shouldOrganizationUseTotp: Boolean, @SerialName("reprompt") - val reprompt: Int, + val reprompt: CipherRepromptTypeJson, @SerialName("edit") val shouldEdit: Boolean, @@ -540,20 +536,19 @@ data class SyncResponseJson( @SerialName("passwordHistory") val passwordHistory: List?, - // TODO Serialize revision date in BIT-636 @SerialName("revisionDate") - val revisionDate: String?, + @Contextual + val revisionDate: LocalDateTime?, - // TODO Parse type enum in BIT-636 @SerialName("type") - val type: Int, + val type: CipherTypeJson, @SerialName("login") val login: Login, - // TODO Serialize creation date in BIT-636 @SerialName("creationDate") - val creationDate: String?, + @Contextual + val creationDate: LocalDateTime?, @SerialName("secureNote") val secureNote: SecureNote, @@ -564,9 +559,9 @@ data class SyncResponseJson( @SerialName("organizationId") val organizationId: String?, - // TODO Serialize deleted date in BIT-636 @SerialName("deletedDate") - val deletedDate: String?, + @Contextual + val deletedDate: LocalDateTime?, @SerialName("identity") val identity: Identity, @@ -657,7 +652,7 @@ data class SyncResponseJson( /** * Represents a field in the vault response. * - * @property linkedId The linked ID of the field (nullable). + * @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). @@ -665,14 +660,13 @@ data class SyncResponseJson( @Serializable data class Field( @SerialName("linkedId") - val linkedId: String?, + val linkedIdType: LinkedIdTypeJson?, @SerialName("name") val name: String?, - // TODO Parse type enum in BIT-636 @SerialName("type") - val type: Int, + val type: FieldTypeJson, @SerialName("value") val value: String?, @@ -779,9 +773,9 @@ data class SyncResponseJson( @SerialName("password") val password: String?, - // TODO Serialize password revision date in BIT-636 @SerialName("passwordRevisionDate") - val passwordRevisionDate: String?, + @Contextual + val passwordRevisionDate: LocalDateTime?, @SerialName("autofillOnPageLoad") val shouldAutofillOnPageLoad: Boolean?, @@ -795,13 +789,13 @@ data class SyncResponseJson( /** * Represents a URI in the vault response. * - * @property match The match of the URI. + * @property uriMatchType The match type of the URI. * @property uri The actual string representing the URI (nullable). */ @Serializable data class Uri( @SerialName("match") - val match: Int, + val uriMatchType: UriMatchTypeJson, @SerialName("uri") val uri: String?, @@ -819,9 +813,9 @@ data class SyncResponseJson( @SerialName("password") val password: String, - // TODO Serialize last used date in BIT-636 @SerialName("lastUsedDate") - val lastUsedDate: String, + @Contextual + val lastUsedDate: LocalDateTime, ) /** @@ -831,9 +825,8 @@ data class SyncResponseJson( */ @Serializable data class SecureNote( - // TODO Parse type enum in BIT-636 @SerialName("type") - val type: Int, + val type: SecureNoteTypeJson, ) } @@ -865,9 +858,9 @@ data class SyncResponseJson( @SerialName("notes") val notes: String?, - // TODO Serialize revision date in BIT-636 @SerialName("revisionDate") - val revisionDate: String, + @Contextual + val revisionDate: LocalDateTime, @SerialName("maxAccessCount") val maxAccessCount: Int?, @@ -875,9 +868,8 @@ data class SyncResponseJson( @SerialName("hideEmail") val shouldHideEmail: Boolean, - // TODO Parse type enum in BIT-636 @SerialName("type") - val type: Int, + val type: SendTypeJson, @SerialName("accessId") val accessId: String?, @@ -888,9 +880,9 @@ data class SyncResponseJson( @SerialName("file") val file: File, - // TODO Serialize deletion date in BIT-636 @SerialName("deletionDate") - val deletionDate: String, + @Contextual + val deletionDate: LocalDateTime, @SerialName("name") val name: String?, @@ -907,9 +899,9 @@ data class SyncResponseJson( @SerialName("key") val key: String?, - // TODO Serialize expiration date in BIT-636 @SerialName("expirationDate") - val expirationDate: String?, + @Contextual + val expirationDate: LocalDateTime?, ) { /** * Represents a file in the vault response. diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/UriMatchTypeJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/UriMatchTypeJson.kt new file mode 100644 index 000000000..2c10eaf7d --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/UriMatchTypeJson.kt @@ -0,0 +1,50 @@ +package com.x8bit.bitwarden.data.vault.datasource.network.model + +import com.x8bit.bitwarden.data.platform.datasource.network.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, +} + +private class UriMatchTypeSerializer : + BaseEnumeratedIntSerializer(UriMatchTypeJson.values()) diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/network/serializer/LocalDateTimeSerializerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/network/serializer/LocalDateTimeSerializerTest.kt new file mode 100644 index 000000000..62c04e25d --- /dev/null +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/network/serializer/LocalDateTimeSerializerTest.kt @@ -0,0 +1,96 @@ +package com.x8bit.bitwarden.data.platform.datasource.network.serializer + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.modules.SerializersModule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import java.time.LocalDateTime + +class LocalDateTimeSerializerTest { + private val json = Json { + serializersModule = SerializersModule { + contextual(LocalDateTime::class, LocalDateTimeSerializer()) + } + } + + @Test + fun `properly deserializes raw JSON to LocalDate`() { + assertEquals( + LocalDateTimeData( + dataAsLocalDateTime = LocalDateTime.of( + 2023, + 10, + 6, + 17, + 22, + 28, + 440000000, + ), + ), + json.decodeFromString( + """ + { + "dataAsLocalDateTime": "2023-10-06T17:22:28.44Z" + } + """, + ), + ) + } + @Test + fun `properly deserializes raw JSON with nano seconds to LocalDate`() { + assertEquals( + LocalDateTimeData( + dataAsLocalDateTime = LocalDateTime.of( + 2023, + 10, + 6, + 17, + 22, + 28, + 446666700, + ), + ), + json.decodeFromString( + """ + { + "dataAsLocalDateTime": "2023-10-06T17:22:28.4466667Z" + } + """, + ), + ) + } + + @Test + fun `properly serializes external model back to raw JSON`() { + assertEquals( + json.parseToJsonElement( + """ + { + "dataAsLocalDateTime": "2023-10-06T17:22:28.44Z" + } + """, + ), + json.encodeToJsonElement( + LocalDateTimeData( + dataAsLocalDateTime = LocalDateTime.of( + 2023, + 10, + 6, + 17, + 22, + 28, + 440000000, + ), + ), + ), + ) + } +} + +@Serializable +private data class LocalDateTimeData( + @Serializable(LocalDateTimeSerializer::class) + val dataAsLocalDateTime: LocalDateTime, +)