VaultEntry.kt

3.7 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    /** SHA-256 signing-certificate fingerprints bound to native app associations. */20    val nativeSignerDigests: Set<String>? = null,21    val totp: String? = null,22    val notes: String? = null,23    val breach: Int? = null,24    val passwordChangedAt: Long? = null,25    /** Past passwords, newest first. Captured automatically on password change. */26    val passwordHistory: List<PasswordHistoryItem>? = null,27    val canary: Canary? = null,28    val createdAt: Long,29    val modifiedAt: Long,30    val deletedAt: Long? = null,31    val tags: List<String>? = null,32    // MN-5 (verified vs peach-browser `shared/backup.ts`): the browser stores passkey33    // entries FLAT on the entry — rpId/rpName/credentialId/publicKeyCose/userHandle/34    // userName/userDisplayName/algorithm/signCount directly, NOT under a nested object.35    // The flat fields below use the SAME camelCase names, so they serialize compatibly36    // with the browser and need no @SerialName. `privateKeyJwk` is preserved as a37    // compact JSON string internally and emitted as a JSON object in PeachScript;38    // Android Credential Provider signing still needs a future ceremony implementation.39    val passkey: PasskeyData? = null,40    val signCount: Int? = null,41    val lastUsedAt: Long? = null,42    val cardholderName: String? = null,43    val cardNumber: String? = null,44    val expMonth: String? = null,45    val expYear: String? = null,46    val cvc: String? = null,47    val cardNickname: String? = null,48    /**49     * "visa" | "mastercard" | "amex" | "discover" | "unknown" — derivable from cardNumber.50     * Serialized as "network" to match the browser's card shape so it survives sync (MF-3).51     */52    @SerialName("network")53    val cardNetwork: String? = null,54    /**55     * Last 4 PAN digits. Derived from cardNumber on save (see VaultRepository) and56     * serialized as "last4" for browser parity — the browser stores this separately57     * rather than deriving it at render time (MF-3).58     */59    @SerialName("last4")60    val last4: String? = null,61    val rpId: String? = null,62    val rpName: String? = null,63    val credentialId: String? = null,64    val publicKeyCose: String? = null,65    @Serializable(with = JwkStringSerializer::class)66    val privateKeyJwk: String? = null,67    val userHandle: String? = null,68    val userName: String? = null,69    val userDisplayName: String? = null,70    val algorithm: Int? = null,71    val aaguid: String? = null,72    val backupEligible: Boolean? = null,73    val backupState: Boolean? = null,74    val browser: String? = null,75    val transports: List<String>? = null,76) : Parcelable7778fun VaultEntry.isLogin() = type == "login" || type == null79fun VaultEntry.isNote() = type == "note"80fun VaultEntry.isCard() = type == "card"81fun VaultEntry.isDeleted() = deletedAt != null82fun VaultEntry.hasTOTP() = !totp.isNullOrBlank()83fun VaultEntry.hasPasskey() = passkey != null84fun VaultEntry.isPasskeyOnly() = hasPasskey() && password.isNullOrBlank() && totp.isNullOrBlank() && email.isNullOrBlank()85fun VaultEntry.isBreach() = (breach ?: 0) > 08687fun VaultEntry.domainKey(): String? {88    val urlStr = url ?: return null89    return try {90        val host = java.net.URL(urlStr).host91        host.removePrefix("www.")92    } catch (_: Exception) {93        null94    }95}