Skip to content

Commit 46dd4a5

Browse files
Merge branch 'master' into mrschmidt-closewhenidle
2 parents c25a96e + 369b411 commit 46dd4a5

File tree

7 files changed

+268
-20
lines changed

7 files changed

+268
-20
lines changed

packages/auth/src/authstorage.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,16 @@ fireauth.authStorage.Key;
137137
* some mobile browsers. A localStorage change in the foreground window
138138
* will not be detected in the background window via the storage event.
139139
* This was detected in iOS 7.x mobile browsers.
140+
* @param {boolean} webStorageSupported Whether browser web storage is
141+
* supported.
140142
* @constructor @struct @final
141143
*/
142144
fireauth.authStorage.Manager = function(
143145
namespace,
144146
separator,
145147
safariLocalStorageNotSynced,
146-
runsInBackground) {
148+
runsInBackground,
149+
webStorageSupported) {
147150
/** @const @private {string} Storage namespace. */
148151
this.namespace_ = namespace;
149152
/** @const @private {string} Storage namespace key separator. */
@@ -159,6 +162,8 @@ fireauth.authStorage.Manager = function(
159162
* mobile browsers.
160163
*/
161164
this.runsInBackground_ = runsInBackground;
165+
/** @const @private {boolean} Whether browser web storage is supported. */
166+
this.webStorageSupported_ = webStorageSupported;
162167

163168
/**
164169
* @const @private {!Object.<string, !Array<function()>>} The storage event
@@ -223,7 +228,8 @@ fireauth.authStorage.Manager.getInstance = function() {
223228
fireauth.authStorage.NAMESPACE_,
224229
fireauth.authStorage.SEPARATOR_,
225230
fireauth.util.isSafariLocalStorageNotSynced(),
226-
fireauth.util.runsInBackground());
231+
fireauth.util.runsInBackground(),
232+
fireauth.util.isWebStorageSupported());
227233
}
228234
return fireauth.authStorage.Manager.instance_;
229235
};
@@ -337,8 +343,7 @@ fireauth.authStorage.Manager.prototype.addListener =
337343
function(dataKey, id, listener) {
338344
var key = this.getKeyName_(dataKey, id);
339345
// Initialize local map for current key if web storage is supported.
340-
if (typeof goog.global['localStorage'] !== 'undefined' &&
341-
typeof goog.global['localStorage']['getItem'] === 'function') {
346+
if (this.webStorageSupported_) {
342347
this.localMap_[key] = goog.global['localStorage']['getItem'](key);
343348
}
344349
if (goog.object.isEmpty(this.listeners_)) {
@@ -401,7 +406,9 @@ fireauth.authStorage.Manager.prototype.startListeners_ = function() {
401406
if (!this.runsInBackground_ &&
402407
// Add an exception for IE11 and Edge browsers, we should stick to
403408
// indexedDB in that case.
404-
!fireauth.util.isLocalStorageNotSynchronized()) {
409+
!fireauth.util.isLocalStorageNotSynchronized() &&
410+
// Confirm browser web storage is supported as polling relies on it.
411+
this.webStorageSupported_) {
405412
this.startManualListeners_();
406413
}
407414
};

packages/auth/src/rpchandler.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,11 @@ fireauth.RpcHandler.validateVerifyAssertionForExistingResponse_ =
14991499
fireauth.RpcHandler.ServerError.USER_NOT_FOUND) {
15001500
// This corresponds to user-not-found.
15011501
throw new fireauth.AuthError(fireauth.authenum.Error.USER_DELETED);
1502+
} else if (response[fireauth.RpcHandler.AuthServerField.ERROR_MESSAGE]) {
1503+
// Construct developer facing error message from server code in errorMessage
1504+
// field.
1505+
throw fireauth.RpcHandler.getDeveloperErrorFromCode_(
1506+
response[fireauth.RpcHandler.AuthServerField.ERROR_MESSAGE]);
15021507
}
15031508
// Need confirmation should not be returned when do not create new user flag
15041509
// is set.
@@ -1543,6 +1548,11 @@ fireauth.RpcHandler.validateVerifyAssertionResponse_ = function(response) {
15431548
// owner of the account and then link to the returned credential here.
15441549
response['code'] = fireauth.authenum.Error.EMAIL_EXISTS;
15451550
error = fireauth.AuthErrorWithCredential.fromPlainObject(response);
1551+
} else if (response[fireauth.RpcHandler.AuthServerField.ERROR_MESSAGE]) {
1552+
// Construct developer facing error message from server code in errorMessage
1553+
// field.
1554+
error = fireauth.RpcHandler.getDeveloperErrorFromCode_(
1555+
response[fireauth.RpcHandler.AuthServerField.ERROR_MESSAGE]);
15461556
}
15471557
// If error found, throw it.
15481558
if (error) {
@@ -1979,6 +1989,30 @@ fireauth.RpcHandler.hasError_ = function(resp) {
19791989
};
19801990

19811991

1992+
/**
1993+
* Returns the developer facing error corresponding to the server code provided.
1994+
* @param {string} serverErrorCode The server error message.
1995+
* @return {!fireauth.AuthError} The corresponding error object.
1996+
* @private
1997+
*/
1998+
fireauth.RpcHandler.getDeveloperErrorFromCode_ = function(serverErrorCode) {
1999+
// Encapsulate the server error code in a typical server error response with
2000+
// the code populated within. This will convert the response to a developer
2001+
// facing one.
2002+
return fireauth.RpcHandler.getDeveloperError_({
2003+
'error': {
2004+
'errors': [
2005+
{
2006+
'message': serverErrorCode
2007+
}
2008+
],
2009+
'code': 400,
2010+
'message': serverErrorCode
2011+
}
2012+
});
2013+
};
2014+
2015+
19822016
/**
19832017
* Converts a server response with errors to a developer-facing AuthError.
19842018
* @param {!Object} response The server response.

packages/auth/src/storage/indexeddb.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,11 @@ fireauth.storage.IndexedDB.prototype.initializeDbAndRun_ =
220220
* @return {boolean} Whether indexedDB is available or not.
221221
*/
222222
fireauth.storage.IndexedDB.isAvailable = function() {
223-
return !!window.indexedDB;
223+
try {
224+
return !!goog.global['indexedDB'];
225+
} catch (e) {
226+
return false;
227+
}
224228
};
225229

226230

packages/auth/src/storage/localstorage.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,20 @@ fireauth.storage.LocalStorage = function() {
5555

5656
/** @return {?Storage|undefined} The global localStorage instance. */
5757
fireauth.storage.LocalStorage.getGlobalStorage = function() {
58-
return goog.global['localStorage'];
58+
try {
59+
var storage = goog.global['localStorage'];
60+
// Try editing web storage. If an error is thrown, it may be disabled.
61+
var key = fireauth.util.generateEventId();
62+
if (storage) {
63+
storage['setItem'](key, '1');
64+
storage['removeItem'](key);
65+
}
66+
return storage;
67+
} catch (e) {
68+
// In some cases, browsers with web storage disabled throw an error simply
69+
// on access.
70+
return null;
71+
}
5972
};
6073

6174

packages/auth/src/storage/sessionstorage.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,20 @@ fireauth.storage.SessionStorage = function() {
5454

5555
/** @return {?Storage|undefined} The global sessionStorage instance. */
5656
fireauth.storage.SessionStorage.getGlobalStorage = function() {
57-
return goog.global['sessionStorage'];
57+
try {
58+
var storage = goog.global['sessionStorage'];
59+
// Try editing web storage. If an error is thrown, it may be disabled.
60+
var key = fireauth.util.generateEventId();
61+
if (storage) {
62+
storage['setItem'](key, '1');
63+
storage['removeItem'](key);
64+
}
65+
return storage;
66+
} catch (e) {
67+
// In some cases, browsers with web storage disabled throw an error simply
68+
// on access.
69+
return null;
70+
}
5871
};
5972

6073

packages/auth/test/authstorage_test.js

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function tearDown() {
7777
* synchronized manager instance used for testing.
7878
*/
7979
function getDefaultManagerInstance() {
80-
return new fireauth.authStorage.Manager('firebase', ':', false, true);
80+
return new fireauth.authStorage.Manager('firebase', ':', false, true, true);
8181
}
8282

8383

@@ -404,7 +404,8 @@ function testGetSet_persistentStorage_noId() {
404404

405405

406406
function testAddRemoveListeners_localStorage() {
407-
var manager = new fireauth.authStorage.Manager('name', ':', false, true);
407+
var manager =
408+
new fireauth.authStorage.Manager('name', ':', false, true, true);
408409
var listener1 = goog.testing.recordFunction();
409410
var listener2 = goog.testing.recordFunction();
410411
var listener3 = goog.testing.recordFunction();
@@ -470,7 +471,8 @@ function testAddRemoveListeners_localStorage() {
470471

471472

472473
function testAddRemoveListeners_localStorage_nullKey() {
473-
var manager = new fireauth.authStorage.Manager('name', ':', false, true);
474+
var manager =
475+
new fireauth.authStorage.Manager('name', ':', false, true, true);
474476
var listener1 = goog.testing.recordFunction();
475477
var listener2 = goog.testing.recordFunction();
476478
var listener3 = goog.testing.recordFunction();
@@ -522,7 +524,8 @@ function testAddRemoveListeners_localStorage_ie10() {
522524
function() {
523525
return true;
524526
});
525-
var manager = new fireauth.authStorage.Manager('name', ':', false, true);
527+
var manager =
528+
new fireauth.authStorage.Manager('name', ':', false, true, true);
526529
var listener1 = goog.testing.recordFunction();
527530
var listener2 = goog.testing.recordFunction();
528531
var listener3 = goog.testing.recordFunction();
@@ -637,7 +640,8 @@ function testAddRemoveListeners_indexeddb() {
637640
function() {
638641
return mockIndexeddb;
639642
});
640-
var manager = new fireauth.authStorage.Manager('name', ':', false, true);
643+
var manager =
644+
new fireauth.authStorage.Manager('name', ':', false, true, true);
641645
var listener1 = goog.testing.recordFunction();
642646
var listener2 = goog.testing.recordFunction();
643647
var listener3 = goog.testing.recordFunction();
@@ -714,7 +718,8 @@ function testAddRemoveListeners_indexeddb_cannotRunInBackground() {
714718
return mockIndexeddb;
715719
});
716720
// Cannot run in the background.
717-
var manager = new fireauth.authStorage.Manager('name', ':', false, false);
721+
var manager =
722+
new fireauth.authStorage.Manager('name', ':', false, false, true);
718723
var listener1 = goog.testing.recordFunction();
719724
var listener2 = goog.testing.recordFunction();
720725
var listener3 = goog.testing.recordFunction();
@@ -757,7 +762,7 @@ function testAddRemoveListeners_indexeddb_cannotRunInBackground() {
757762

758763
function testSafariLocalStorageSync_newEvent() {
759764
var manager =
760-
new fireauth.authStorage.Manager('firebase', ':', true, true);
765+
new fireauth.authStorage.Manager('firebase', ':', true, true, true);
761766
// Simulate Safari bug.
762767
stubs.replace(
763768
fireauth.util,
@@ -797,7 +802,7 @@ function testSafariLocalStorageSync_cannotRunInBackground() {
797802
// Realistically only storage event should trigger here.
798803
// Test when new data is added to storage.
799804
var manager =
800-
new fireauth.authStorage.Manager('firebase', ':', true, false);
805+
new fireauth.authStorage.Manager('firebase', ':', true, false, true);
801806
// Simulate Safari bug.
802807
stubs.replace(
803808
fireauth.util,
@@ -837,7 +842,7 @@ function testSafariLocalStorageSync_deletedEvent() {
837842
// Realistically only storage event should trigger here.
838843
// Test when old data is deleted from storage.
839844
var manager =
840-
new fireauth.authStorage.Manager('firebase', ':', true, true);
845+
new fireauth.authStorage.Manager('firebase', ':', true, true, true);
841846
var key1 = {'name': 'authEvent', 'persistent': true};
842847
// Simulate Safari bug.
843848
stubs.replace(
@@ -879,7 +884,7 @@ function testRunsInBackground_storageEventMode() {
879884
var key = {name: 'authEvent', persistent: 'local'};
880885
var storageKey = 'firebase:authEvent:appId1';
881886
var manager = new fireauth.authStorage.Manager(
882-
'firebase', ':', false, false);
887+
'firebase', ':', false, false, true);
883888
var listener1 = goog.testing.recordFunction();
884889
var expectedEvent = {
885890
type: 'signInViaPopup',
@@ -923,6 +928,49 @@ function testRunsInBackground_storageEventMode() {
923928
}
924929

925930

931+
function testRunsInBackground_webStorageNotSupported() {
932+
// Test when browser does not run in the background and web storage is not
933+
// supported. Polling should not be turned on.
934+
var key = {name: 'authEvent', persistent: 'local'};
935+
var storageKey = 'firebase:authEvent:appId1';
936+
// Simulate manager doesn't support web storage and can't run in the
937+
// background. Normally when a browser can't run in the background, polling is
938+
// enabled.
939+
var manager = new fireauth.authStorage.Manager(
940+
'firebase', ':', false, false, false);
941+
var listener1 = goog.testing.recordFunction();
942+
var expectedEvent = {
943+
type: 'signInViaPopup',
944+
eventId: '1234',
945+
callbackUrl: 'http://www.example.com/#oauthResponse',
946+
sessionId: 'SESSION_ID'
947+
};
948+
949+
// Add listener.
950+
manager.addListener(key, appId, listener1);
951+
// Test that polling function is not set by updating localStorage with some
952+
// data. This should not happen realistically when web storage is disabled.
953+
window.localStorage.setItem(storageKey, JSON.stringify(expectedEvent));
954+
// Run clock.
955+
clock.tick(1000);
956+
// Listener should not trigger.
957+
assertEquals(0, listener1.getCallCount());
958+
// Clear storage.
959+
window.localStorage.clear();
960+
// Run clock.
961+
clock.tick(1000);
962+
// Listener should not trigger.
963+
assertEquals(0, listener1.getCallCount());
964+
// Save Auth event and confirm listener not triggered.
965+
// This normally simulates polling.
966+
window.localStorage.setItem(storageKey, JSON.stringify(expectedEvent));
967+
// Run clock.
968+
clock.tick(1000);
969+
// Listener should not trigger.
970+
assertEquals(0, listener1.getCallCount());
971+
}
972+
973+
926974
function testRunsInBackground_pollingMode() {
927975
// Test when browser does not run in the background while another tab is in
928976
// foreground.
@@ -932,7 +980,7 @@ function testRunsInBackground_pollingMode() {
932980
var key = {name: 'authEvent', persistent: 'local'};
933981
var storageKey = 'firebase:authEvent:appId1';
934982
var manager = new fireauth.authStorage.Manager(
935-
'firebase', ':', false, false);
983+
'firebase', ':', false, false, true);
936984
var listener1 = goog.testing.recordFunction();
937985
var expectedEvent = {
938986
type: 'signInViaPopup',
@@ -984,7 +1032,7 @@ function testRunsInBackground_currentTabChangesIgnored() {
9841032
var key = {name: 'authEvent', persistent: 'local'};
9851033
var storageKey = 'firebase:authEvent:appId1';
9861034
var manager = new fireauth.authStorage.Manager(
987-
'firebase', ':', false, false);
1035+
'firebase', ':', false, false, true);
9881036
var listener1 = goog.testing.recordFunction();
9891037
var expectedEvent = {
9901038
type: 'signInViaPopup',

0 commit comments

Comments
 (0)