package com.peachpasswords.passkeys import android.os.Build import android.os.CancellationSignal import androidx.credentials.provider.BeginCreateCredentialRequest import androidx.credentials.provider.BeginCreateCredentialResponse import androidx.credentials.provider.BeginGetCredentialRequest import androidx.credentials.provider.BeginGetCredentialResponse import androidx.credentials.provider.CredentialProviderService import androidx.credentials.provider.ProviderClearCredentialStateRequest import android.os.OutcomeReceiver import androidx.credentials.exceptions.ClearCredentialException import androidx.credentials.exceptions.CreateCredentialException import androidx.credentials.exceptions.GetCredentialException import androidx.annotation.RequiresApi /** * Android 14+ credential provider surface for Peach passkeys. * * The Begin* callbacks MUST be answered or the Credential Manager times out and * reports a provider error; the previous scaffold left them uninvoked. This * version always completes the callbacks with a valid (currently empty) * response, so Peach registers cleanly as a provider without erroring. * * Surfacing real passkey entries and running the WebAuthn ceremony is gated on * one data-model addition: [com.peachpasswords.vault.PasskeyData] stores only * the public COSE key, so an assertion (get) cannot be signed yet. Completing * passkeys means persisting the per-credential ES256 private key in the vault * envelope, then emitting PublicKeyCredentialEntry rows here with a * PendingIntent into the same branded sheet the autofill picker uses. */ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) class PeachCredentialProviderService : CredentialProviderService() { override fun onBeginGetCredentialRequest( request: BeginGetCredentialRequest, cancellationSignal: CancellationSignal, callback: OutcomeReceiver, ) { callback.onResult(BeginGetCredentialResponse()) } override fun onBeginCreateCredentialRequest( request: BeginCreateCredentialRequest, cancellationSignal: CancellationSignal, callback: OutcomeReceiver, ) { callback.onResult(BeginCreateCredentialResponse()) } override fun onClearCredentialStateRequest( request: ProviderClearCredentialStateRequest, cancellationSignal: CancellationSignal, callback: OutcomeReceiver, ) { callback.onResult(null) } }