1414
1515package com.firebase.ui.auth.compose.configuration
1616
17+ import android.content.Context
1718import android.graphics.Color
19+ import android.util.Log
1820import androidx.compose.ui.graphics.vector.ImageVector
21+ import com.firebase.ui.auth.AuthUI
22+ import com.firebase.ui.auth.R
23+ import com.firebase.ui.auth.util.Preconditions
24+ import com.firebase.ui.auth.util.data.PhoneNumberUtils
25+ import com.firebase.ui.auth.util.data.ProviderAvailability
1926import com.google.firebase.auth.ActionCodeSettings
2027import com.google.firebase.auth.EmailAuthProvider
2128import com.google.firebase.auth.FacebookAuthProvider
@@ -78,6 +85,14 @@ abstract class AuthProvider(open val providerId: String) {
7885 */
7986 val isEmailLinkSignInEnabled : Boolean = false ,
8087
88+ /* *
89+ * Forces email link sign-in to complete on the same device that initiated it.
90+ *
91+ * When enabled, prevents email links from being opened on different devices,
92+ * which is required for security when upgrading anonymous users. Defaults to true.
93+ */
94+ val isEmailLinkForceSameDeviceEnabled : Boolean = true ,
95+
8196 /* *
8297 * Settings for email link actions.
8398 */
@@ -100,11 +115,10 @@ abstract class AuthProvider(open val providerId: String) {
100115 ) : AuthProvider(providerId = Provider .EMAIL .id) {
101116 fun validate () {
102117 if (isEmailLinkSignInEnabled) {
103- val actionCodeSettings = actionCodeSettings
104- ? : requireNotNull(actionCodeSettings) {
105- " ActionCodeSettings cannot be null when using " +
106- " email link sign in."
107- }
118+ val actionCodeSettings = requireNotNull(actionCodeSettings) {
119+ " ActionCodeSettings cannot be null when using " +
120+ " email link sign in."
121+ }
108122
109123 check(actionCodeSettings.canHandleCodeInApp()) {
110124 " You must set canHandleCodeInApp in your " +
@@ -118,6 +132,11 @@ abstract class AuthProvider(open val providerId: String) {
118132 * Phone number authentication provider configuration.
119133 */
120134 class Phone (
135+ /* *
136+ * The phone number in international format.
137+ */
138+ val defaultNumber : String? ,
139+
121140 /* *
122141 * The default country code to pre-select.
123142 */
@@ -147,7 +166,31 @@ abstract class AuthProvider(open val providerId: String) {
147166 * Enables automatic retrieval of the SMS code. Defaults to true.
148167 */
149168 val isAutoRetrievalEnabled : Boolean = true
150- ) : AuthProvider(providerId = Provider .PHONE .id)
169+ ) : AuthProvider(providerId = Provider .PHONE .id) {
170+ fun validate () {
171+ defaultNumber?.let {
172+ check(PhoneNumberUtils .isValid(it)) {
173+ " Invalid phone number: $it "
174+ }
175+ }
176+
177+ defaultCountryCode?.let {
178+ check(PhoneNumberUtils .isValidIso(it)) {
179+ " Invalid country iso: $it "
180+ }
181+ }
182+
183+ allowedCountries?.forEach { code ->
184+ check(
185+ PhoneNumberUtils .isValidIso(code) ||
186+ PhoneNumberUtils .isValid(code)
187+ ) {
188+ " Invalid input: You must provide a valid country iso (alpha-2) " +
189+ " or code (e-164). e.g. 'us' or '+1'. Invalid code: $code "
190+ }
191+ }
192+ }
193+ }
151194
152195 /* *
153196 * Google Sign-In provider configuration.
@@ -186,12 +229,40 @@ abstract class AuthProvider(open val providerId: String) {
186229 providerId = Provider .GOOGLE .id,
187230 scopes = scopes,
188231 customParameters = customParameters
189- )
232+ ) {
233+ fun validate (context : Context ) {
234+ if (serverClientId == null ) {
235+ Preconditions .checkConfigured(
236+ context,
237+ " Check your google-services plugin configuration, the" +
238+ " default_web_client_id string wasn't populated." ,
239+ R .string.default_web_client_id
240+ )
241+ } else {
242+ require(serverClientId.isNotBlank()) {
243+ " Server client ID cannot be blank."
244+ }
245+ }
246+
247+ val hasEmailScope = scopes.contains(" email" )
248+ if (! hasEmailScope) {
249+ Log .w(
250+ " AuthProvider.Google" ,
251+ " The scopes do not include 'email'. In most cases this is a mistake!"
252+ )
253+ }
254+ }
255+ }
190256
191257 /* *
192258 * Facebook Login provider configuration.
193259 */
194260 class Facebook (
261+ /* *
262+ * The Facebook application ID.
263+ */
264+ val applicationId : String? = null ,
265+
195266 /* *
196267 * The list of scopes (permissions) to request. Defaults to email and public_profile.
197268 */
@@ -210,7 +281,30 @@ abstract class AuthProvider(open val providerId: String) {
210281 providerId = Provider .FACEBOOK .id,
211282 scopes = scopes,
212283 customParameters = customParameters
213- )
284+ ) {
285+ fun validate (context : Context ) {
286+ if (! ProviderAvailability .IS_FACEBOOK_AVAILABLE ) {
287+ throw RuntimeException (
288+ " Facebook provider cannot be configured " +
289+ " without dependency. Did you forget to add " +
290+ " 'com.facebook.android:facebook-login:VERSION' dependency?"
291+ )
292+ }
293+
294+ if (applicationId == null ) {
295+ Preconditions .checkConfigured(
296+ context,
297+ " Facebook provider unconfigured. Make sure to " +
298+ " add a `facebook_application_id` string or provide applicationId parameter." ,
299+ R .string.facebook_application_id
300+ )
301+ } else {
302+ require(applicationId.isNotBlank()) {
303+ " Facebook application ID cannot be blank"
304+ }
305+ }
306+ }
307+ }
214308
215309 /* *
216310 * Twitter/X authentication provider configuration.
@@ -314,7 +408,16 @@ abstract class AuthProvider(open val providerId: String) {
314408 /* *
315409 * Anonymous authentication provider. It has no configurable properties.
316410 */
317- object Anonymous : AuthProvider(providerId = Provider .ANONYMOUS .id)
411+ object Anonymous : AuthProvider(providerId = Provider .ANONYMOUS .id) {
412+ fun validate (providers : List <AuthProvider >) {
413+ if (providers.size == 1 && providers.first() is Anonymous ) {
414+ throw IllegalStateException (
415+ " Sign in as guest cannot be the only sign in method. " +
416+ " In this case, sign the user in anonymously your self; no UI is needed."
417+ )
418+ }
419+ }
420+ }
318421
319422 /* *
320423 * A generic OAuth provider for any unsupported provider.
@@ -353,5 +456,15 @@ abstract class AuthProvider(open val providerId: String) {
353456 providerId = providerId,
354457 scopes = scopes,
355458 customParameters = customParameters
356- )
459+ ) {
460+ fun validate () {
461+ require(providerId.isNotBlank()) {
462+ " Provider ID cannot be null or empty"
463+ }
464+
465+ require(buttonLabel.isNotBlank()) {
466+ " Button label cannot be null or empty"
467+ }
468+ }
469+ }
357470}
0 commit comments