VaultEntry.kt

3.6 KB · raw

1package com.peachpasswords.vault23import android.os.Parcelable4import kotlinx.parcelize.Parcelize5import kotlinx.serialization.SerialName6import kotlinx.serialization.Serializable78@Parcelize9@Serializable10data class VaultEntry(11    val id: String,12    val type: String? = null,13    val title: String,14    val username: String? = null,15    val email: String? = null,16    val password: String? = null,17    val url: String? = null,18    val additionalUrls: List<String>? = null,19    val totp: String? = null,20    val notes: String? = null,21    val breach: Int? = null,22    val passwordChangedAt: Long? = null,23    /** Past passwords, newest first. Captured automatically on password change. */24    val passwordHistory: List<PasswordHistoryItem>? = null,25    val canary: Canary? = null,26    val createdAt: Long,27    val modifiedAt: Long,28    val deletedAt: Long? = null,29    val tags: List<String>? = null,30    // MN-5 (verified vs peach-browser `shared/backup.ts`): the browser stores passkey31    // entries FLAT on the entry — rpId/rpName/credentialId/publicKeyCose/userHandle/32    // userName/userDisplayName/algorithm/signCount directly, NOT under a nested object.33    // The flat fields below use the SAME camelCase names, so they serialize compatibly34    // with the browser and need no @SerialName. `privateKeyJwk` is preserved as a35    // compact JSON string internally and emitted as a JSON object in PeachScript;36    // Android Credential Provider signing still needs a future ceremony implementation.37    val passkey: PasskeyData? = null,38    val signCount: Int? = null,39    val lastUsedAt: Long? = null,40    val cardholderName: String? = null,41    val cardNumber: String? = null,42    val expMonth: String? = null,43    val expYear: String? = null,44    val cvc: String? = null,45    val cardNickname: String? = null,46    /**47     * "visa" | "mastercard" | "amex" | "discover" | "unknown" — derivable from cardNumber.48     * Serialized as "network" to match the browser's card shape so it survives sync (MF-3).49     */50    @SerialName("network")51    val cardNetwork: String? = null,52    /**53     * Last 4 PAN digits. Derived from cardNumber on save (see VaultRepository) and54     * serialized as "last4" for browser parity — the browser stores this separately55     * rather than deriving it at render time (MF-3).56     */57    @SerialName("last4")58    val last4: String? = null,59    val rpId: String? = null,60    val rpName: String? = null,61    val credentialId: String? = null,62    val publicKeyCose: String? = null,63    @Serializable(with = JwkStringSerializer::class)64    val privateKeyJwk: String? = null,65    val userHandle: String? = null,66    val userName: String? = null,67    val userDisplayName: String? = null,68    val algorithm: Int? = null,69    val aaguid: String? = null,70    val backupEligible: Boolean? = null,71    val backupState: Boolean? = null,72    val browser: String? = null,73    val transports: List<String>? = null,74) : Parcelable7576fun VaultEntry.isLogin() = type == "login" || type == null77fun VaultEntry.isNote() = type == "note"78fun VaultEntry.isCard() = type == "card"79fun VaultEntry.isDeleted() = deletedAt != null80fun VaultEntry.hasTOTP() = !totp.isNullOrBlank()81fun VaultEntry.hasPasskey() = passkey != null82fun VaultEntry.isPasskeyOnly() = hasPasskey() && password.isNullOrBlank() && totp.isNullOrBlank() && email.isNullOrBlank()83fun VaultEntry.isBreach() = (breach ?: 0) > 08485fun VaultEntry.domainKey(): String? {86    val urlStr = url ?: return null87    return try {88        val host = java.net.URL(urlStr).host89        host.removePrefix("www.")90    } catch (_: Exception) {91        null92    }93}