From 89041d31375343a4056c1ab3744e6438d39a70fc Mon Sep 17 00:00:00 2001 From: Artem Chepurnyi Date: Wed, 31 Jul 2024 13:13:52 +0300 Subject: [PATCH] improvement: Bitwarden checksum URI generation #498 --- .../core/store/bitwarden/BitwardenCipher.kt | 4 ++++ .../provider/bitwarden/api/SyncEngine.kt | 21 ++++++++++++++++++- .../provider/bitwarden/crypto/CipherCrypto.kt | 1 + .../bitwarden/crypto/CipherDecoder.kt | 1 + .../bitwarden/entity/LoginUriEntity.kt | 3 +++ .../bitwarden/entity/api/LoginUriRequest.kt | 3 +++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/core/store/bitwarden/BitwardenCipher.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/core/store/bitwarden/BitwardenCipher.kt index 28c353c..ab4ff0d 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/core/store/bitwarden/BitwardenCipher.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/core/store/bitwarden/BitwardenCipher.kt @@ -210,11 +210,15 @@ data class BitwardenCipher( val version: Long, ) + @optics @Serializable data class Uri( val uri: String? = null, + val uriChecksumBase64: String? = null, val match: MatchType? = null, ) { + companion object; + @Serializable enum class MatchType { Domain, diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/api/SyncEngine.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/api/SyncEngine.kt index b7f88af..2b59e9a 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/api/SyncEngine.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/api/SyncEngine.kt @@ -19,6 +19,8 @@ import com.artemchep.keyguard.core.store.bitwarden.BitwardenProfile import com.artemchep.keyguard.core.store.bitwarden.BitwardenSend import com.artemchep.keyguard.core.store.bitwarden.BitwardenService import com.artemchep.keyguard.core.store.bitwarden.BitwardenToken +import com.artemchep.keyguard.core.store.bitwarden.login +import com.artemchep.keyguard.core.store.bitwarden.uris import com.artemchep.keyguard.data.Database import com.artemchep.keyguard.platform.recordException import com.artemchep.keyguard.provider.bitwarden.api.builder.api @@ -575,7 +577,24 @@ class SyncEngine( localReEncoder = { model -> model }, - localDecoder = { local, remote -> + localDecoder = { rawLocal, remote -> + // Inject the URL checksums into the list of URLs before + // processing the entry. + val local = BitwardenCipher.login.uris.modify(rawLocal) { uris -> + uris + .map { uri -> + if (uri.uriChecksumBase64 != null) return@map uri + val uriChecksumBase64 = kotlin.run { + val rawHash = + cryptoGenerator.hashSha256(uri.uri.orEmpty().toByteArray()) + base64Service.encodeToString(rawHash) + } + uri.copy( + uriChecksumBase64 = uriChecksumBase64, + ) + } + } + val itemKey = local.keyBase64 ?.let(base64Service::decode) val ( diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherCrypto.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherCrypto.kt index d7152b5..7da1cac 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherCrypto.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherCrypto.kt @@ -85,6 +85,7 @@ fun BitwardenCipher.Login.Uri.transform( crypto: BitwardenCrCta, ) = copy( uri = crypto.transformString(uri.orEmpty()), + uriChecksumBase64 = uriChecksumBase64?.let(crypto::transformString), ) @JvmName("encryptListOfBitwardenCipherLoginFido2Credentials") diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherDecoder.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherDecoder.kt index 6b913e5..bec38d0 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherDecoder.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/crypto/CipherDecoder.kt @@ -80,6 +80,7 @@ fun BitwardenCipher.Companion.encrypted( val match = it.match?.domain() BitwardenCipher.Login.Uri( uri = it.uri, + uriChecksumBase64 = it.uriChecksum, match = match, ) }, diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/LoginUriEntity.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/LoginUriEntity.kt index 531df5f..0d74e8d 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/LoginUriEntity.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/LoginUriEntity.kt @@ -9,6 +9,9 @@ data class LoginUriEntity( @JsonNames("uri") @SerialName("Uri") val uri: String? = null, + @JsonNames("uriChecksum") + @SerialName("UriChecksum") + val uriChecksum: String? = null, @JsonNames("match") @SerialName("Match") val match: UriMatchTypeEntity? = null, diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/api/LoginUriRequest.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/api/LoginUriRequest.kt index c99b40f..fd12bba 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/api/LoginUriRequest.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/provider/bitwarden/entity/api/LoginUriRequest.kt @@ -10,6 +10,8 @@ import kotlinx.serialization.Serializable data class LoginUriRequest( @SerialName("uri") val uri: String, + @SerialName("uriChecksum") + val uriChecksum: String?, @SerialName("match") val match: UriMatchTypeEntity?, ) { @@ -21,6 +23,7 @@ fun LoginUriRequest.Companion.of( ) = kotlin.run { LoginUriRequest( uri = requireNotNull(model.uri) { "Login URI request must have a non-null URI!" }, + uriChecksum = model.uriChecksumBase64, match = model.match?.let(UriMatchTypeEntity::of), ) }