improvement: Bitwarden checksum URI generation #498

This commit is contained in:
Artem Chepurnyi 2024-07-31 13:13:52 +03:00
parent f723997abb
commit 89041d3137
6 changed files with 32 additions and 1 deletions

View File

@ -210,11 +210,15 @@ data class BitwardenCipher(
val version: Long, val version: Long,
) )
@optics
@Serializable @Serializable
data class Uri( data class Uri(
val uri: String? = null, val uri: String? = null,
val uriChecksumBase64: String? = null,
val match: MatchType? = null, val match: MatchType? = null,
) { ) {
companion object;
@Serializable @Serializable
enum class MatchType { enum class MatchType {
Domain, Domain,

View File

@ -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.BitwardenSend
import com.artemchep.keyguard.core.store.bitwarden.BitwardenService import com.artemchep.keyguard.core.store.bitwarden.BitwardenService
import com.artemchep.keyguard.core.store.bitwarden.BitwardenToken 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.data.Database
import com.artemchep.keyguard.platform.recordException import com.artemchep.keyguard.platform.recordException
import com.artemchep.keyguard.provider.bitwarden.api.builder.api import com.artemchep.keyguard.provider.bitwarden.api.builder.api
@ -575,7 +577,24 @@ class SyncEngine(
localReEncoder = { model -> localReEncoder = { model ->
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 val itemKey = local.keyBase64
?.let(base64Service::decode) ?.let(base64Service::decode)
val ( val (

View File

@ -85,6 +85,7 @@ fun BitwardenCipher.Login.Uri.transform(
crypto: BitwardenCrCta, crypto: BitwardenCrCta,
) = copy( ) = copy(
uri = crypto.transformString(uri.orEmpty()), uri = crypto.transformString(uri.orEmpty()),
uriChecksumBase64 = uriChecksumBase64?.let(crypto::transformString),
) )
@JvmName("encryptListOfBitwardenCipherLoginFido2Credentials") @JvmName("encryptListOfBitwardenCipherLoginFido2Credentials")

View File

@ -80,6 +80,7 @@ fun BitwardenCipher.Companion.encrypted(
val match = it.match?.domain() val match = it.match?.domain()
BitwardenCipher.Login.Uri( BitwardenCipher.Login.Uri(
uri = it.uri, uri = it.uri,
uriChecksumBase64 = it.uriChecksum,
match = match, match = match,
) )
}, },

View File

@ -9,6 +9,9 @@ data class LoginUriEntity(
@JsonNames("uri") @JsonNames("uri")
@SerialName("Uri") @SerialName("Uri")
val uri: String? = null, val uri: String? = null,
@JsonNames("uriChecksum")
@SerialName("UriChecksum")
val uriChecksum: String? = null,
@JsonNames("match") @JsonNames("match")
@SerialName("Match") @SerialName("Match")
val match: UriMatchTypeEntity? = null, val match: UriMatchTypeEntity? = null,

View File

@ -10,6 +10,8 @@ import kotlinx.serialization.Serializable
data class LoginUriRequest( data class LoginUriRequest(
@SerialName("uri") @SerialName("uri")
val uri: String, val uri: String,
@SerialName("uriChecksum")
val uriChecksum: String?,
@SerialName("match") @SerialName("match")
val match: UriMatchTypeEntity?, val match: UriMatchTypeEntity?,
) { ) {
@ -21,6 +23,7 @@ fun LoginUriRequest.Companion.of(
) = kotlin.run { ) = kotlin.run {
LoginUriRequest( LoginUriRequest(
uri = requireNotNull(model.uri) { "Login URI request must have a non-null URI!" }, uri = requireNotNull(model.uri) { "Login URI request must have a non-null URI!" },
uriChecksum = model.uriChecksumBase64,
match = model.match?.let(UriMatchTypeEntity::of), match = model.match?.let(UriMatchTypeEntity::of),
) )
} }