1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.credentials
18 
19 import android.content.ComponentName
20 import android.os.Bundle
21 
22 /**
23  * Allows extending custom versions of GetCredentialOptions for unique use cases.
24  *
25  * If you get a [GetCustomCredentialOption] instead of a type-safe option class such as
26  * [GetPasswordOption], [GetPublicKeyCredentialOption], etc., then you should check if you have any
27  * other library at interest that supports this custom [type] of credential option, and if so use
28  * its parsing utilities to resolve to a type-safe class within that library.
29  *
30  * Note: The Bundle keys for [requestData] and [candidateQueryData] should not be in the form of
31  * `androidx.credentials.*` as they are reserved for internal use by this androidx library.
32  *
33  * The [typePriorityHint] bit helps decide where the credential will be displayed on the selector.
34  * It is used with more importance than signals like 'last recently used' but with less importance
35  * than other signals, such as the ordering of displayed accounts. It is expected to be one of the
36  * defined `CredentialOption.PRIORITY_*` constants. By default, [GetCustomCredentialOption] will
37  * have [CredentialOption.PRIORITY_DEFAULT], [GetPasswordOption] will have
38  * [CredentialOption.PRIORITY_PASSWORD_OR_SIMILAR] and [GetPublicKeyCredentialOption] will have
39  * [CredentialOption.PRIORITY_PASSKEY_OR_SIMILAR]. It is expected that [GetCustomCredentialOption]
40  * types will remain unchanged unless strong reasons arise and cannot ever have
41  * [CredentialOption.PRIORITY_PASSKEY_OR_SIMILAR]. Given passkeys prevent many security threats that
42  * other credentials do not, we enforce that nothing is shown higher than passkey types in order to
43  * provide end users with the safest credentials first. See the spec
44  * [here](https://w3c.github.io/webauthn/) for more information on passkeys.
45  *
46  * @property type the credential type determined by the credential-type-specific subclass (e.g. the
47  *   type for [GetPasswordOption] is [PasswordCredential.TYPE_PASSWORD_CREDENTIAL] and for
48  *   [GetPublicKeyCredentialOption] is [PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL])
49  * @property requestData the request data in the [Bundle] format
50  * @property candidateQueryData the partial request data in the [Bundle] format that will be sent to
51  *   the provider during the initial candidate query stage, which will not contain sensitive user
52  *   information
53  * @property isSystemProviderRequired true if must only be fulfilled by a system provider and false
54  *   otherwise
55  * @property isAutoSelectAllowed whether a credential entry will be automatically chosen if it is
56  *   the only one available option
57  * @property allowedProviders a set of provider service [ComponentName] allowed to receive this
58  *   option (Note: a [SecurityException] will be thrown if it is set as non-empty but your app does
59  *   not have android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS; for API level < 34, this
60  *   property will not take effect and you should control the allowed provider via
61  *   [library dependencies](https://developer.android.com/training/sign-in/passkeys#add-dependencies))
62  * @property typePriorityHint sets the priority of this entry, which defines how it appears in the
63  *   credential selector amongst the signals used to order the entries, set to
64  *   [CredentialOption.PRIORITY_DEFAULT] by default; see [CredentialOption] for more information
65  */
66 open class GetCustomCredentialOption
67 internal constructor(
68     requestData: Bundle,
69     type: String,
70     candidateQueryData: Bundle,
71     isSystemProviderRequired: Boolean,
72     isAutoSelectAllowed: Boolean = false,
73     allowedProviders: Set<ComponentName> = emptySet(),
74     typePriorityHint: @PriorityHints Int = PRIORITY_DEFAULT
75 ) :
76     CredentialOption(
77         type = type,
78         requestData = requestData,
79         candidateQueryData = candidateQueryData,
80         isSystemProviderRequired = isSystemProviderRequired,
81         isAutoSelectAllowed = isAutoSelectAllowed,
82         allowedProviders = allowedProviders,
83         typePriorityHint = typePriorityHint,
84     ) {
85 
86     init {
<lambda>null87         require(type.isNotEmpty()) { "type should not be empty" }
<lambda>null88         require(typePriorityHint != CredentialOption.PRIORITY_PASSKEY_OR_SIMILAR) {
89             "Custom types should not have passkey level priority."
90         }
91     }
92 
93     /**
94      * Allows extending custom versions of GetCredentialOptions for unique use cases.
95      *
96      * If you get a [GetCustomCredentialOption] instead of a type-safe option class such as
97      * [GetPasswordOption], [GetPublicKeyCredentialOption], etc., then you should check if you have
98      * any other library at interest that supports this custom [type] of credential option, and if
99      * so use its parsing utilities to resolve to a type-safe class within that library.
100      *
101      * Note: The Bundle keys for [requestData] and [candidateQueryData] should not be in the form of
102      * `androidx.credentials.*` as they are reserved for internal use by this androidx library.
103      *
104      * @param type the credential type determined by the credential-type-specific subclass generated
105      *   for custom use cases
106      * @param requestData the request data in the [Bundle] format, generated for custom use cases
107      *   (note: bundle keys in the form of `androidx.credentials.*` and `android.credentials.*` are
108      *   reserved for internal library usage)
109      * @param candidateQueryData the partial request data in the [Bundle] format that will be sent
110      *   to the provider during the initial candidate query stage, which should not contain
111      *   sensitive user information (note: bundle keys in the form of `androidx.credentials.*` and
112      *   `android.credentials.*` are reserved for internal library usage)
113      * @param isSystemProviderRequired true if must only be fulfilled by a system provider and false
114      *   otherwise
115      * @param isAutoSelectAllowed defines if a credential entry will be automatically chosen if it
116      *   is the only one available option, false by default
117      * @param allowedProviders a set of provider service [ComponentName] allowed to receive this
118      *   option (Note: a [SecurityException] will be thrown if it is set as non-empty but your app
119      *   does not have android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS; for API level <
120      *   34, this property will not take effect and you should control the allowed provider via
121      *   [library dependencies](https://developer.android.com/training/sign-in/passkeys#add-dependencies))
122      * @throws IllegalArgumentException If [type] is empty
123      * @throws NullPointerException If [requestData] or [type] is null
124      */
125     @JvmOverloads
126     constructor(
127         type: String,
128         requestData: Bundle,
129         candidateQueryData: Bundle,
130         isSystemProviderRequired: Boolean,
131         isAutoSelectAllowed: Boolean = false,
132         allowedProviders: Set<ComponentName> = emptySet(),
133     ) : this(
134         requestData,
135         type,
136         candidateQueryData,
137         isSystemProviderRequired,
138         isAutoSelectAllowed,
139         allowedProviders
140     )
141 
142     /**
143      * Allows extending custom versions of GetCredentialOptions for unique use cases.
144      *
145      * If you get a [GetCustomCredentialOption] instead of a type-safe option class such as
146      * [GetPasswordOption], [GetPublicKeyCredentialOption], etc., then you should check if you have
147      * any other library at interest that supports this custom [type] of credential option, and if
148      * so use its parsing utilities to resolve to a type-safe class within that library.
149      *
150      * Note: The Bundle keys for [requestData] and [candidateQueryData] should not be in the form of
151      * `androidx.credentials.*` as they are reserved for internal use by this androidx library.
152      *
153      * The [typePriorityHint] bit helps decide where the credential will be displayed on the
154      * selector. It is expected that [GetCustomCredentialOption] types will remain unchanged unless
155      * strong reasons arise and cannot ever have [CredentialOption.PRIORITY_PASSKEY_OR_SIMILAR].
156      * Given passkeys prevent many security threats that other credentials do not, we enforce that
157      * nothing is shown higher than passkey types in order to provide end users with the safest
158      * credentials first. See the spec [here](https://w3c.github.io/webauthn/) for more information
159      * on passkeys.
160      *
161      * @param type the credential type determined by the credential-type-specific subclass generated
162      *   for custom use cases
163      * @param requestData the request data in the [Bundle] format, generated for custom use cases
164      *   (note: bundle keys in the form of `androidx.credentials.*` and `android.credentials.*` are
165      *   reserved for internal library usage)
166      * @param candidateQueryData the partial request data in the [Bundle] format that will be sent
167      *   to the provider during the initial candidate query stage, which should not contain
168      *   sensitive user information (note: bundle keys in the form of `androidx.credentials.*` and
169      *   `android.credentials.*` are reserved for internal library usage)
170      * @param isSystemProviderRequired true if must only be fulfilled by a system provider and false
171      *   otherwise
172      * @param isAutoSelectAllowed defines if a credential entry will be automatically chosen if it
173      *   is the only one available option, false by default
174      * @param allowedProviders a set of provider service [ComponentName] allowed to receive this
175      *   option (Note: a [SecurityException] will be thrown if it is set as non-empty but your app
176      *   does not have android.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS; for API level <
177      *   34, this property will not take effect and you should control the allowed provider via
178      *   [library dependencies](https://developer.android.com/training/sign-in/passkeys#add-dependencies))
179      * @param typePriorityHint sets the priority of this entry, which defines how it appears in the
180      *   credential selector, with less precedence than account ordering but more precedence than
181      *   last used time; see [CredentialOption] and [CredentialOption] for more information
182      * @throws IllegalArgumentException If [type] is empty
183      * @throws NullPointerException If [requestData] or [type] is null
184      */
185     constructor(
186         type: String,
187         requestData: Bundle,
188         candidateQueryData: Bundle,
189         isSystemProviderRequired: Boolean,
190         isAutoSelectAllowed: Boolean = false,
191         allowedProviders: Set<ComponentName> = emptySet(),
192         typePriorityHint: @PriorityHints Int = PRIORITY_DEFAULT,
193     ) : this(
194         requestData,
195         type,
196         candidateQueryData,
197         isSystemProviderRequired,
198         isAutoSelectAllowed,
199         allowedProviders,
200         typePriorityHint
201     )
202 }
203