AutofillSave.kt

3.0 KB · raw

1package com.peachpasswords.autofill23import com.peachpasswords.shared.getDisplayDomain4import com.peachpasswords.vault.VaultEntry5import com.peachpasswords.vault.isLogin67internal data class AutofillSaveDraft(8    val origin: String,9    val isWebOrigin: Boolean,10    val identity: String?,11    val identityIsEmail: Boolean,12    val password: String,13    val totp: String?,14)1516internal sealed interface AutofillSavePlan {17    data class Add(val entry: VaultEntry) : AutofillSavePlan18    data class Update(val entry: VaultEntry) : AutofillSavePlan19}2021internal fun autofillSaveDraft(parsed: ParsedStructure): AutofillSaveDraft? {22    val password = parsed.passwordValue?.trim().orEmpty()23    if (password.isBlank()) return null24    val origin = parsed.origin?.trim().orEmpty()25    if (origin.isBlank()) return null26    val identity = (parsed.emailValue ?: parsed.usernameValue)?.trim()?.takeIf { it.isNotBlank() }27    return AutofillSaveDraft(28        origin = origin,29        isWebOrigin = parsed.webDomain != null,30        identity = identity,31        identityIsEmail = parsed.emailValue?.isNotBlank() == true || identity?.contains("@") == true,32        password = password,33        totp = parsed.otpValue?.trim()?.takeIf { it.isNotBlank() },34    )35}3637internal fun planAutofillSave(entries: List<VaultEntry>, draft: AutofillSaveDraft): AutofillSavePlan {38    val target = findAutofillUpdateTarget(entries, draft)39    return if (target == null) {40        AutofillSavePlan.Add(draft.toEntry())41    } else {42        AutofillSavePlan.Update(43            target.copy(44                username = if (!draft.identityIsEmail) draft.identity ?: target.username else target.username,45                email = if (draft.identityIsEmail) draft.identity ?: target.email else target.email,46                password = draft.password,47                totp = draft.totp ?: target.totp,48            ),49        )50    }51}5253private fun findAutofillUpdateTarget(entries: List<VaultEntry>, draft: AutofillSaveDraft): VaultEntry? {54    val candidates = if (draft.isWebOrigin) {55        AutofillResponseBuilder.matchEntries(entries, draft.origin).hits56    } else {57        entries.filter { it.url == draft.origin }58    }.filter { it.deletedAt == null && it.isLogin() }5960    val identity = draft.identity?.lowercase()61    if (identity != null) {62        candidates.firstOrNull { entry ->63            entry.username?.lowercase() == identity || entry.email?.lowercase() == identity64        }?.let { return it }65    }66    return candidates.singleOrNull()67}6869private fun AutofillSaveDraft.toEntry(): VaultEntry {70    val title = if (isWebOrigin) getDisplayDomain(origin) else origin71    return VaultEntry(72        id = "",73        type = "login",74        title = title,75        username = if (!identityIsEmail) identity else null,76        email = if (identityIsEmail) identity else null,77        password = password,78        url = if (isWebOrigin && !origin.contains("://")) "https://$origin" else origin,79        totp = totp,80        createdAt = 0,81        modifiedAt = 0,82    )83}