@@ -34,6 +34,7 @@ import androidx.credentials.exceptions.GetCredentialUnknownException
34
34
import androidx.credentials.provider.BiometricPromptResult
35
35
import androidx.credentials.provider.CallingAppInfo
36
36
import androidx.credentials.provider.PendingIntentHandler
37
+ import androidx.credentials.provider.ProviderGetCredentialRequest
37
38
import androidx.fragment.app.FragmentActivity
38
39
import com.example.android.authentication.myvault.AppDependencies
39
40
import com.example.android.authentication.myvault.R
@@ -73,10 +74,31 @@ class GetPasskeyActivity : FragmentActivity() {
73
74
}
74
75
75
76
/* *
76
- * Handle the intent for get public key credential (passkey)
77
+ * Handles the intent for retrieving a public key credential (passkey).
78
+ *
79
+ * <p>This method processes the incoming intent to retrieve a passkey. It
80
+ * extracts the necessary data from the intent, including the
81
+ * {@link ProviderGetCredentialRequest} and additional request information.
82
+ * It then checks for errors and proceeds to configure the passkey assertion.
83
+ *
84
+ * <p>The method performs the following steps:
85
+ * <ol>
86
+ * <li>Retrieves the request information and the {@link ProviderGetCredentialRequest}
87
+ * from the intent.</li>
88
+ * <li>Checks if the request information or the request itself is null. If so,
89
+ * it sets up a failure response and finishes the activity.</li>
90
+ * <li>Retrieves the {@link androidx.credentials.provider.BiometricPromptResult}
91
+ * from the request.</li>
92
+ * <li>Checks for errors in the biometric flow using {@link #isValidBiometricFlowError}.
93
+ * If an error is detected, it returns early.</li>
94
+ * <li>Configures the passkey assertion using {@link #configurePasskeyAssertion}.</li>
95
+ * </ol>
77
96
*/
78
97
private fun handleGetPasskeyIntent () {
98
+ // Retrieve the request information from the intent.
79
99
val requestInfo = intent.getBundleExtra(getString(R .string.vault_data))
100
+
101
+ // Retrieve the boolean indicating if the passkey is auto selected.
80
102
intent.getBooleanExtra(getString(R .string.is_auto_selected), false )
81
103
82
104
/*
@@ -86,31 +108,66 @@ class GetPasskeyActivity : FragmentActivity() {
86
108
*/
87
109
val request = PendingIntentHandler .retrieveProviderGetCredentialRequest(intent)
88
110
111
+ // Check if the request information or the request itself is null.
89
112
if (requestInfo == null || request == null ) {
113
+ // If either is null, set up a failure response and finish the activity.
90
114
setUpFailureResponseAndFinish(getString(R .string.unable_to_retrieve_data_from_intent))
91
115
return
92
116
}
93
117
118
+ // Retrieve the BiometricPromptResult from the request.
94
119
val biometricPromptResult = request.biometricPromptResult
95
120
121
+ // Check if there was an error in the biometric flow.
96
122
if (isValidBiometricFlowError(biometricPromptResult)) return
97
123
98
- val publicKeyCredentialOption = request.credentialOptions[0 ]
124
+ // Configure the passkey assertion.
125
+ configurePasskeyAssertion(
126
+ biometricPromptResult,
127
+ requestInfo,
128
+ request,
129
+ )
130
+ }
131
+
132
+ /* *
133
+ * Configures the passkey assertion process.
134
+ *
135
+ * <p>This method orchestrates the passkey assertion process by retrieving
136
+ * necessary data from the request, validating the calling application, and
137
+ * determining whether to use the biometric or default flow for assertion.
138
+ *
139
+ * @param biometricPromptResult The result of the biometric authentication prompt.
140
+ * @param requestInfo The bundle containing additional request information.
141
+ * @param request The {@link ProviderGetCredentialRequest} containing the
142
+ * credential request details.
143
+ */
144
+ private fun configurePasskeyAssertion (
145
+ biometricPromptResult : BiometricPromptResult ? ,
146
+ requestInfo : Bundle ,
147
+ request : ProviderGetCredentialRequest ,
148
+ ) {
149
+ // Retrieve the encoded credential ID from the request information.
150
+ val credentialIdEncoded = requestInfo.getString(getString(R .string.cred_id))!!
151
+
152
+ // Retrieve the PasskeyItem from the data source using the encoded credential ID.
153
+ val passkey = credentialsDataSource.getPasskey(credentialIdEncoded)!!
99
154
100
- // Extract the GetPublicKeyCredentialOption from the request retrieved above.
155
+ // Extract the GetPublicKeyCredentialOption from the request.
156
+ val publicKeyCredentialOption = request.credentialOptions[0 ]
101
157
val publicKeyRequest = publicKeyCredentialOption as GetPublicKeyCredentialOption
158
+
159
+ // Create a PublicKeyCredentialRequestOptions object from the extracted option.
102
160
val publicKeyRequestOptions = PublicKeyCredentialRequestOptions (
103
161
publicKeyRequest.requestJson,
104
162
)
105
163
106
- val credentialIdEncoded = requestInfo.getString(getString(R .string.cred_id))!!
107
- val passkey = credentialsDataSource.getPasskey(credentialIdEncoded)!!
108
-
164
+ // Decode the credential ID, private key, and UID from their base64 encoded forms.
109
165
val credentialID = b64Decode(credentialIdEncoded)
110
166
val privateKey = b64Decode(passkey.credPrivateKey)
111
167
val uid = b64Decode(passkey.uid)
112
- var callingAppOriginInfo: String? = null
113
168
169
+ // Determine the calling application's origin and validate it.
170
+ var callingAppOriginInfo: String? = null
114
171
if (hasRequestContainsOrigin(request.callingAppInfo)) {
115
172
callingAppOriginInfo = validatePrivilegedCallingApp(
116
173
request.callingAppInfo,
@@ -123,64 +180,19 @@ class GetPasskeyActivity : FragmentActivity() {
123
180
)
124
181
}
125
182
183
+ // Get the origin and package name from the calling app info.
126
184
val origin = appInfoToOrigin(request.callingAppInfo)
127
185
val packageName = request.callingAppInfo.packageName
128
186
187
+ // Convert the decoded private key to an ECPrivateKey.
129
188
val convertedPrivateKey = convertPrivateKey(privateKey)
130
189
131
- // Extract the requestJson and clientDataHash from this option .
190
+ // Extract the client data hash if the calling application's origin is available .
132
191
var clientDataHash: ByteArray? = null
133
192
if (callingAppOriginInfo != null ) {
134
193
clientDataHash = publicKeyRequest.clientDataHash
135
194
}
136
195
137
- configurePasskeyAssertion(
138
- biometricPromptResult,
139
- passkey,
140
- origin,
141
- callingAppOriginInfo,
142
- publicKeyRequestOptions,
143
- uid,
144
- packageName,
145
- clientDataHash,
146
- convertedPrivateKey,
147
- credentialID,
148
- )
149
- }
150
-
151
- /* *
152
- * Configures the passkey assertion based on the biometric authentication result.
153
- *
154
- * <p>This method determines whether to use the biometric flow or the default
155
- * flow for asserting a passkey. If the {@link BiometricPromptResult} indicates
156
- * successful authentication, it calls {@link #assertPasskeyWithBiometricFlow}
157
- * to proceed with the biometric flow. Otherwise, it calls
158
- * {@link #assertPasskeyWithDefaultFlow} to proceed with the default flow.
159
- *
160
- * @param biometricPromptResult The result of the biometric authentication prompt.
161
- * @param passkey The {@link PasskeyItem} containing the passkey details.
162
- * @param origin The origin of the calling application.
163
- * @param callingAppOriginInfo The origin information of the calling application, if available.
164
- * @param publicKeyRequestOptions The {@link PublicKeyCredentialRequestOptions} containing the
165
- * request details.
166
- * @param uid The unique identifier associated with the passkey.
167
- * @param packageName The package name of the calling application.
168
- * @param clientDataHash The client data hash, if available.
169
- * @param convertedPrivateKey The converted private key for the passkey.
170
- * @param credentialID The credential ID of the passkey.
171
- */
172
- private fun configurePasskeyAssertion (
173
- biometricPromptResult : BiometricPromptResult ? ,
174
- passkey : PasskeyItem ,
175
- origin : String ,
176
- callingAppOriginInfo : String? ,
177
- publicKeyRequestOptions : PublicKeyCredentialRequestOptions ,
178
- uid : ByteArray ,
179
- packageName : String ,
180
- clientDataHash : ByteArray? ,
181
- convertedPrivateKey : ECPrivateKey ,
182
- credentialID : ByteArray ,
183
- ) {
184
196
// Check if the biometric prompt result indicates successful authentication.
185
197
if (biometricPromptResult?.authenticationResult != null ) {
186
198
// If biometric authentication was successful, use the biometric flow.
0 commit comments