Skip to content

Commit bd71044

Browse files
Googlerbojeil-google
authored andcommitted
[firebase-release] Updated FirebaseUI for web to 2.4.0.
- Removes hard coded QUOTA_EXCEEDED phone auth error. Instead we will use whatever the Auth API returns. - Updates the FirebaseUI demo app to install as a standalone PWA when added to home screen on an Android device. - Support prefilling the default phone number by passing a loginHint in the configuration only when phone auth provider is the only provider. - Support prefilling the default national number along with default country only when phone auth provider is the only provider. - Updates saucelabs tests: replace Safari 6 with 7 and removes IE9. - Remove autoescape="strict" attributes from Soy templates. - Uses session persistence when supported on the internal temporary auth instance to avoid dangling auth states. - Modified reCAPTCHA "I am not a Robot" button to be more responsive in narrow screens. - Adds a continue button to redirect to the continueUrl if available in the password reset and email verification action widgets. PiperOrigin-RevId: 171213094 Change-Id: I72097a0e356f9748ffd2599b97484601e0a1bd28
1 parent 3a67397 commit bd71044

25 files changed

+751
-59
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,23 @@ ui.start('#firebaseui-auth-container', {
467467
size: 'normal', // 'invisible' or 'compact'
468468
badge: 'bottomleft' //' bottomright' or 'inline' applies to invisible.
469469
},
470-
defaultCountry: 'GB' // Set default country to the United Kingdom (+44).
470+
defaultCountry: 'GB', // Set default country to the United Kingdom (+44).
471+
// For prefilling the national number, set defaultNationNumber.
472+
// This will only be observed if only phone Auth provider is used since
473+
// for multiple providers, the NASCAR screen will always render first
474+
// with a 'sign in with phone number' button.
475+
defaultNationalNumber: '1234567890',
476+
// You can also pass the full phone number string instead of the
477+
// 'defaultCountry' and 'defaultNationalNumber'. However, in this case,
478+
// the first country ID that matches the country code will be used to
479+
// populate the country selector. So for countries that share the same
480+
// country code, the selected country may not be the expected one.
481+
// In that case, pass the 'defaultCountry' instead to ensure the exact
482+
// country is selected. The 'defaultCountry' and 'defaultNationaNumber'
483+
// will always have higher priority than 'loginHint' which will be ignored
484+
// in their favor. In this case, the default country will be 'GB' even
485+
// though 'loginHint' specified the country code as '+1'.
486+
loginHint: '+11234567890'
471487
}
472488
]
473489
});

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

demo/public/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<title>FirebaseUI Auth Demo</title>
6+
<link rel="manifest" href="manifest.json">
67
<script src="https://www.gstatic.com/firebasejs/live/4.1/firebase.js"></script>
78
<script src="config.js"></script>
89
<script src="common.js"></script>

demo/public/manifest.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "FirebaseUI Demo",
3+
"short_name": "FirebaseUIDemo",
4+
"start_url": "/",
5+
"display": "standalone",
6+
"background_color": "#fff",
7+
"lang": "en-US",
8+
"description": "FirebaseUI Demo application.",
9+
"prefer_related_applications": false,
10+
"theme_color": "#fff",
11+
"scope": "/",
12+
"orientation": "portrait-primary"
13+
}

javascript/testing/auth.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,28 @@ var FakeAuthClient = function(app) {
5353
FakeAuthClient.base(this, 'constructor', asyncMethods);
5454
this.authObservers_ = [];
5555
this.idTokenObservers_ = [];
56+
/** @private {!Array<string>} The list of frameworks logged. */
57+
this.frameworks_ = [];
58+
var self = this;
59+
this['INTERNAL'] = {
60+
logFramework: function(framework) {
61+
self.frameworks_.push(framework);
62+
}
63+
};
5664
};
5765
goog.inherits(FakeAuthClient, MockHelper);
5866

5967

68+
/**
69+
* Asserts the expected list of frameworks IDs are logged.
70+
* @param {!Array<string>} expectedFrameworks The expected list of frameworks
71+
* logged.
72+
*/
73+
FakeAuthClient.prototype.assertFrameworksLogged = function(expectedFrameworks) {
74+
assertArrayEquals(expectedFrameworks, this.frameworks_);
75+
};
76+
77+
6078
/**
6179
* Updates the user with selected properties.
6280
* @param {!Object} props The updated user properties, if null, user is
@@ -175,6 +193,7 @@ FakeAuthClient.AuthAsyncMethod = {
175193
FETCH_PROVIDERS_FOR_EMAIL: 'fetchProvidersForEmail',
176194
GET_REDIRECT_RESULT: 'getRedirectResult',
177195
SEND_PASSWORD_RESET_EMAIL: 'sendPasswordResetEmail',
196+
SET_PERSISTENCE: 'setPersistence',
178197
SIGN_IN_AND_RETRIEVE_DATA_WITH_CREDENTIAL:
179198
'signInAndRetrieveDataWithCredential',
180199
SIGN_IN_WITH_CREDENTIAL: 'signInWithCredential',

javascript/testing/auth_test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ function testFakeAuthClient_setUser() {
128128
}
129129

130130

131+
function testFakeAuthClient_logFramework() {
132+
auth.install();
133+
auth.INTERNAL.logFramework('firebaseui');
134+
auth.INTERNAL.logFramework('angularfire');
135+
auth.assertFrameworksLogged(['firebaseui', 'angularfire']);
136+
}
137+
138+
131139
function testFakeAuthClient_withUser_Success() {
132140
asyncTestCase.waitForSignals(1);
133141
// Test with combination of authentication and user methods.

javascript/ui/page/notice.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ goog.require('firebaseui.auth.ui.page.Base');
3838
* @param {function(ARG_TYPES, null=, Object.<string, *>=):*} template The Soy
3939
* template for the component.
4040
* @param {ARG_TYPES=} opt_templateData The data for the template.
41-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
42-
* button is clicked.
41+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
42+
* continue button is clicked.
4343
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
4444
* @param {string=} opt_uiLabel The optional UI label.
4545
* @constructor
@@ -99,8 +99,8 @@ goog.mixin(
9999
/**
100100
* Password recovery email sent notice UI component.
101101
* @param {string} email The email to which the recovery email has been sent.
102-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
103-
* button is clicked.
102+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
103+
* continue button is clicked.
104104
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
105105
* @constructor
106106
* @extends {firebaseui.auth.ui.page.Notice}
@@ -125,8 +125,8 @@ goog.inherits(firebaseui.auth.ui.page.PasswordRecoveryEmailSent,
125125

126126
/**
127127
* Email verification success notice UI component.
128-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
129-
* button is clicked.
128+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
129+
* continue button is clicked.
130130
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
131131
* @constructor
132132
* @extends {firebaseui.auth.ui.page.Notice}
@@ -151,8 +151,8 @@ goog.inherits(firebaseui.auth.ui.page.EmailVerificationSuccess,
151151

152152
/**
153153
* Email verification failure notice UI component.
154-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
155-
* button is clicked.
154+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
155+
* continue button is clicked.
156156
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
157157
* @constructor
158158
* @extends {firebaseui.auth.ui.page.Notice}
@@ -177,8 +177,8 @@ goog.inherits(firebaseui.auth.ui.page.EmailVerificationFailure,
177177

178178
/**
179179
* Password reset success notice UI component.
180-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
181-
* button is clicked.
180+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
181+
* continue button is clicked.
182182
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
183183
* @constructor
184184
* @extends {firebaseui.auth.ui.page.Notice}
@@ -203,8 +203,8 @@ goog.inherits(firebaseui.auth.ui.page.PasswordResetSuccess,
203203

204204
/**
205205
* Password reset failure notice UI component.
206-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
207-
* button is clicked.
206+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
207+
* continue button is clicked.
208208
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
209209
* @constructor
210210
* @extends {firebaseui.auth.ui.page.Notice}
@@ -228,8 +228,8 @@ goog.inherits(firebaseui.auth.ui.page.PasswordResetFailure,
228228

229229
/**
230230
* Email change revoke failure notice UI component.
231-
* @param {function()=} opt_onContinueClick Callback to invoke when the continue
232-
* button is clicked.
231+
* @param {?function()=} opt_onContinueClick Callback to invoke when the
232+
* continue button is clicked.
233233
* @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
234234
* @constructor
235235
* @extends {firebaseui.auth.ui.page.Notice}

javascript/utils/phonenumber.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
goog.provide('firebaseui.auth.PhoneNumber');
1616

1717
goog.require('firebaseui.auth.data.country');
18+
goog.require('goog.string');
1819

1920

2021
/**
@@ -31,6 +32,46 @@ firebaseui.auth.PhoneNumber = function(countryId, nationalNumber) {
3132
};
3233

3334

35+
/** @const {string} The ID of the default country (currently USA). */
36+
firebaseui.auth.PhoneNumber.DEFAULT_COUNTRY_ID = '1-US-0';
37+
38+
39+
/**
40+
* Converts a phone number string to a firebaseui.auth.PhoneNumber object.
41+
* Returns null if invalid.
42+
* @param {string} phoneNumberStr The full phone number string.
43+
* @return {?firebaseui.auth.PhoneNumber} The corresponding
44+
* `firebaseui.auth.PhoneNumber` representation.
45+
*/
46+
firebaseui.auth.PhoneNumber.fromString = function(phoneNumberStr) {
47+
// Ideally libPhoneNumber should be used to parse the phone number string but
48+
// that dependency is too large to bundle with FirebaseUI-web, so we will
49+
// attempt a best effort approach to parse the 2 components.
50+
var trimmedPhoneNumber = goog.string.trim(phoneNumberStr);
51+
// Get matching countries if national number countains it.
52+
var countries = firebaseui.auth.data.country.LOOKUP_TREE.search(
53+
trimmedPhoneNumber);
54+
if (countries.length > 0) {
55+
var countryId;
56+
// Parse the country ID and national number components.
57+
// If the country code is +1, use US as default code.
58+
// Otherwise, just pick the first country.
59+
if (countries[0].e164_cc == '1') {
60+
countryId = firebaseui.auth.PhoneNumber.DEFAULT_COUNTRY_ID;
61+
} else {
62+
countryId = countries[0].e164_key;
63+
}
64+
// Get the national number. Add the + char to the e164_cc string.
65+
var nationalNumber =
66+
trimmedPhoneNumber.substr(countries[0].e164_cc.length + 1);
67+
// Return the phone number object.
68+
return new firebaseui.auth.PhoneNumber(
69+
countryId, goog.string.trim(nationalNumber));
70+
}
71+
return null;
72+
};
73+
74+
3475
/**
3576
* @return {string} The full phone number.
3677
*/
@@ -42,3 +83,13 @@ firebaseui.auth.PhoneNumber.prototype.getPhoneNumber = function() {
4283
}
4384
return '+' + countryData.e164_cc + this.nationalNumber;
4485
};
86+
87+
88+
/**
89+
* @return {?firebaseui.auth.data.country.Country} The country corresponding to
90+
* the phone number's country ID.
91+
*/
92+
firebaseui.auth.PhoneNumber.prototype.getCountry = function() {
93+
return firebaseui.auth.data.country.getCountryByKey(
94+
this.countryId);
95+
};

javascript/utils/phonenumber_test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,56 @@ function testPhoneNumber_badCountryId() {
4242
phoneNumber.getPhoneNumber();
4343
});
4444
}
45+
46+
47+
function testPhoneNumber_fromString() {
48+
// Empty string.
49+
assertNull(firebaseui.auth.PhoneNumber.fromString(''));
50+
51+
// Missing plus sign.
52+
assertNull(firebaseui.auth.PhoneNumber.fromString('11234567890'));
53+
54+
// Invalid.
55+
assertNull(firebaseui.auth.PhoneNumber.fromString('bla1234567890'));
56+
57+
// Valid number with +1 code should always map to US.
58+
assertObjectEquals(
59+
new firebaseui.auth.PhoneNumber('1-US-0', '1234567890'),
60+
firebaseui.auth.PhoneNumber.fromString('+11234567890'));
61+
62+
// Phone number with no national number should still be accepted.
63+
assertObjectEquals(
64+
new firebaseui.auth.PhoneNumber('1-US-0', ''),
65+
firebaseui.auth.PhoneNumber.fromString('+1'));
66+
67+
// Other codes that are shared will just pick the first match instead of the
68+
// more likely 44-GB-0 country code.
69+
assertObjectEquals(
70+
new firebaseui.auth.PhoneNumber('44-GG-0', '1234567890'),
71+
firebaseui.auth.PhoneNumber.fromString('+441234567890'));
72+
73+
// Parsing should not reformat the number.
74+
assertObjectEquals(
75+
new firebaseui.auth.PhoneNumber('1-US-0', '(123) 456-7890'),
76+
firebaseui.auth.PhoneNumber.fromString(' +1 (123) 456-7890 '));
77+
assertObjectEquals(
78+
new firebaseui.auth.PhoneNumber('1-US-0', '(123)456-7890'),
79+
firebaseui.auth.PhoneNumber.fromString('+1(123)456-7890'));
80+
81+
// Parsing a country code that is only used by one country.
82+
assertObjectEquals(
83+
new firebaseui.auth.PhoneNumber('52-MX-0', '1234567890'),
84+
firebaseui.auth.PhoneNumber.fromString('+521234567890'));
85+
}
86+
87+
88+
function testPhoneNumber_getCountry() {
89+
var phoneNumber = new firebaseui.auth.PhoneNumber('52-MX-0', '1234567890');
90+
assertEquals('MX', phoneNumber.getCountry().iso2_cc);
91+
92+
phoneNumber = new firebaseui.auth.PhoneNumber('1-US-0', '1234567890');
93+
assertEquals('US', phoneNumber.getCountry().iso2_cc);
94+
95+
phoneNumber = new firebaseui.auth.PhoneNumber('invalid', '1234567890');
96+
assertNull(phoneNumber.getCountry());
97+
}

javascript/widgets/authui.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ firebaseui.auth.AuthUI = function(auth, opt_appId) {
8686
}
8787
/** @private {!firebase.auth.Auth} The Firebase Auth instance. */
8888
this.auth_ = auth;
89+
// Log FirebaseUI on external Auth instance.
90+
firebaseui.auth.AuthUI.logFirebaseUI_(this.auth_);
8991
var tempApp = firebase.initializeApp({
9092
'apiKey': auth['app']['options']['apiKey'],
9193
'authDomain': auth['app']['options']['authDomain']
@@ -95,6 +97,13 @@ firebaseui.auth.AuthUI = function(auth, opt_appId) {
9597
* instance.
9698
*/
9799
this.tempAuth_ = tempApp.auth();
100+
// Log FirebaseUI on internal Auth instance.
101+
firebaseui.auth.AuthUI.logFirebaseUI_(this.tempAuth_);
102+
// Change persistence to session to avoid the risk of dangling auth states in
103+
// local storage. Check if the current version used, supports it.
104+
if (this.tempAuth_.setPersistence) {
105+
this.tempAuth_.setPersistence(firebase.auth.Auth.Persistence.SESSION);
106+
}
98107
/** @private {string|undefined} The optional app id. */
99108
this.appId_ = opt_appId;
100109
/** @private {!firebaseui.auth.widget.Config} The AuthUI configuration. */
@@ -126,6 +135,19 @@ firebaseui.auth.AuthUI = function(auth, opt_appId) {
126135
};
127136

128137

138+
/**
139+
* Log FirebaseUI framework on the specified Auth instance.
140+
* @param {!firebase.auth.Auth} auth The Auth instance to log FirebaseUI on.
141+
* @private
142+
*/
143+
firebaseui.auth.AuthUI.logFirebaseUI_ = function(auth) {
144+
// INTERNAL.logFramework not supported in older versions.
145+
if (auth && auth['INTERNAL'] && auth['INTERNAL']['logFramework']) {
146+
auth['INTERNAL']['logFramework'](firebaseui.auth.AuthUI.FRAMEWORK_ID_);
147+
}
148+
};
149+
150+
129151
/** Resets all internal globals. Used for testing only. */
130152
firebaseui.auth.AuthUI.resetAllInternals = function() {
131153
firebaseui.auth.AuthUI.instances_ = {};
@@ -184,6 +206,14 @@ firebaseui.auth.AuthUI.TEMP_APP_NAME_SUFFIX_ = '-firebaseui-temp';
184206
firebaseui.auth.AuthUI.DEFAULT_INSTANCE_KEY_ = '[DEFAULT]';
185207

186208

209+
/**
210+
* The Firebase UI framework ID.
211+
* @const {string}
212+
* @private
213+
*/
214+
firebaseui.auth.AuthUI.FRAMEWORK_ID_ = 'FirebaseUI-web';
215+
216+
187217
/**
188218
* If sign-in succeeded, returns the signed in user. If sign-in was
189219
* unsuccessful, fails with an error. If no redirect operation was called,

0 commit comments

Comments
 (0)