package com.peachpasswords.autofill import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.IntentSender import android.os.Build /** * PendingIntents the autofill surfaces hand to the framework: a no-op * attribution target the inline chip requires, the authentication * IntentSender that opens the branded [AutofillEntryPickerActivity], and the * "open new entry" launcher that the picker fires when the user taps the * "+ Create new entry" affordance. */ object AutofillIntents { const val EXTRA_IDENTITY_ID = "peach.autofill.identityId" const val EXTRA_PASSWORD_ID = "peach.autofill.passwordId" const val EXTRA_OTP_ID = "peach.autofill.otpId" const val EXTRA_ORIGIN = "peach.autofill.origin" const val EXTRA_IS_WEB_ORIGIN = "peach.autofill.isWebOrigin" const val EXTRA_VERIFIED_DOMAINS = "peach.autofill.verifiedDomains" /** Authenticated caller package for web-origin re-verification in the picker. */ const val EXTRA_CALLER_PACKAGE = "peach.autofill.callerPackage" const val EXTRA_CARD_NUMBER_ID = "peach.autofill.cardNumberId" const val EXTRA_CARD_EXP_MONTH_ID = "peach.autofill.cardExpMonthId" const val EXTRA_CARD_EXP_YEAR_ID = "peach.autofill.cardExpYearId" const val EXTRA_CARD_EXP_DATE_ID = "peach.autofill.cardExpDateId" const val EXTRA_CARD_CVC_ID = "peach.autofill.cardCvcId" const val EXTRA_CARD_NAME_ID = "peach.autofill.cardNameId" /** Host-typed username captured by the autofill framework — used to prefill the new-entry editor. */ const val EXTRA_TYPED_USERNAME = "peach.autofill.typedUsername" /** Host-typed email captured by the autofill framework — used to prefill the new-entry editor. */ const val EXTRA_TYPED_EMAIL = "peach.autofill.typedEmail" /** * Sent by [AutofillEntryPickerActivity] to launch MainActivity on the "+ Create * new entry" path. The picker cancels itself and starts MainActivity with the * origin + typed identity so the user can save a brand-new entry pre-filled with * what they had typed on the host page. Carries the same key/value shape as the * update notification's [com.peachpasswords.updates.EXTRA_OPEN_UPDATE]. */ const val EXTRA_OPEN_NEW_ENTRY = "peach.autofill.openNewEntry" const val EXTRA_NEW_ENTRY_URL = "peach.autofill.newEntryUrl" const val EXTRA_NEW_ENTRY_USERNAME = "peach.autofill.newEntryUsername" const val EXTRA_NEW_ENTRY_EMAIL = "peach.autofill.newEntryEmail" private const val REQ_CHIP = 0xC0DE private const val REQ_PICKER = 0xBEEF /** Required attribution for an inline suggestion; tapping it is a no-op. */ fun noopChipIntent(context: Context): PendingIntent { val intent = Intent(context, AutofillEntryPickerActivity::class.java) return PendingIntent.getActivity(context, REQ_CHIP, intent, immutableFlags()) } /** Authentication target for the "Search Peach…" dataset. */ fun pickerIntentSender(context: Context, parsed: ParsedStructure): IntentSender { val intent = Intent(context, AutofillEntryPickerActivity::class.java).apply { putExtra(EXTRA_IDENTITY_ID, parsed.identityId) putExtra(EXTRA_PASSWORD_ID, parsed.passwordId) putExtra(EXTRA_OTP_ID, parsed.otpId) putExtra(EXTRA_ORIGIN, parsed.origin) putExtra(EXTRA_IS_WEB_ORIGIN, parsed.webDomain != null) // Origin trust is re-derived in the picker from raw inputs; // carry the authenticated caller package for web-origin re-verification. putExtra(EXTRA_CALLER_PACKAGE, parsed.packageName) putStringArrayListExtra(EXTRA_VERIFIED_DOMAINS, ArrayList(parsed.verifiedDomains)) putExtra(EXTRA_CARD_NUMBER_ID, parsed.cardNumberId) putExtra(EXTRA_CARD_EXP_MONTH_ID, parsed.cardExpMonthId) putExtra(EXTRA_CARD_EXP_YEAR_ID, parsed.cardExpYearId) putExtra(EXTRA_CARD_EXP_DATE_ID, parsed.cardExpDateId) putExtra(EXTRA_CARD_CVC_ID, parsed.cardCvcId) putExtra(EXTRA_CARD_NAME_ID, parsed.cardNameId) // Mirror the browser's preUsername/preEmail capture so the "+ Create // new entry" path can hand the typed identity to the new-entry editor. // Empty/blank values are dropped — the picker reads the typed username // from the identity field the host anchored on. parsed.usernameValue?.trim()?.takeIf { it.isNotBlank() }?.let { putExtra(EXTRA_TYPED_USERNAME, it) } parsed.emailValue?.trim()?.takeIf { it.isNotBlank() }?.let { putExtra(EXTRA_TYPED_EMAIL, it) } } // Freezing the sender prevents the host app from rewriting origin // extras before the private picker receives them. The picker re-derives // origin trust from raw authenticated inputs in-process. return PendingIntent.getActivity(context, REQ_PICKER, intent, immutableFlags()).intentSender } private fun immutableFlags(): Int = PendingIntent.FLAG_UPDATE_CURRENT or if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0 }