@firebase/auth
Version:
The Firebase Authenticaton component of the Firebase JS SDK.
1,154 lines (1,136 loc) • 80.5 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var index = require('./index-ab3e8e37.js');
var tslib = require('tslib');
var util = require('@firebase/util');
var app = require('@firebase/app');
require('@firebase/logger');
require('@firebase/component');
require('node-fetch');
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function _generateEventId(prefix, digits) {
if (prefix === void 0) { prefix = ''; }
if (digits === void 0) { digits = 10; }
var random = '';
for (var i = 0; i < digits; i++) {
random += Math.floor(Math.random() * 10);
}
return prefix + random;
}
/**
* @license
* Copyright 2020 Google LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var AuthPopup = /** @class */ (function () {
function AuthPopup(window) {
this.window = window;
this.associatedEvent = null;
}
AuthPopup.prototype.close = function () {
if (this.window) {
try {
this.window.close();
}
catch (e) { }
}
};
return AuthPopup;
}());
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Chooses a popup/redirect resolver to use. This prefers the override (which
* is directly passed in), and falls back to the property set on the auth
* object. If neither are available, this function errors w/ an argument error.
*/
function _withDefaultResolver(auth, resolverOverride) {
if (resolverOverride) {
return index._getInstance(resolverOverride);
}
index._assert(auth._popupRedirectResolver, auth, "argument-error" /* ARGUMENT_ERROR */);
return auth._popupRedirectResolver;
}
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var IdpCredential = /** @class */ (function (_super) {
tslib.__extends(IdpCredential, _super);
function IdpCredential(params) {
var _this = _super.call(this, "custom" /* CUSTOM */, "custom" /* CUSTOM */) || this;
_this.params = params;
return _this;
}
IdpCredential.prototype._getIdTokenResponse = function (auth) {
return index.signInWithIdp(auth, this._buildIdpRequest());
};
IdpCredential.prototype._linkToIdToken = function (auth, idToken) {
return index.signInWithIdp(auth, this._buildIdpRequest(idToken));
};
IdpCredential.prototype._getReauthenticationResolver = function (auth) {
return index.signInWithIdp(auth, this._buildIdpRequest());
};
IdpCredential.prototype._buildIdpRequest = function (idToken) {
var request = {
requestUri: this.params.requestUri,
sessionId: this.params.sessionId,
postBody: this.params.postBody,
tenantId: this.params.tenantId,
pendingToken: this.params.pendingToken,
returnSecureToken: true,
returnIdpCredential: true
};
if (idToken) {
request.idToken = idToken;
}
return request;
};
return IdpCredential;
}(index.AuthCredential));
function _signIn(params) {
return index._signInWithCredential(params.auth, new IdpCredential(params), params.bypassAuthState);
}
function _reauth(params) {
var auth = params.auth, user = params.user;
index._assert(user, auth, "internal-error" /* INTERNAL_ERROR */);
return index._reauthenticate(user, new IdpCredential(params), params.bypassAuthState);
}
function _link(params) {
return tslib.__awaiter(this, void 0, void 0, function () {
var auth, user;
return tslib.__generator(this, function (_a) {
auth = params.auth, user = params.user;
index._assert(user, auth, "internal-error" /* INTERNAL_ERROR */);
return [2 /*return*/, index._link(user, new IdpCredential(params), params.bypassAuthState)];
});
});
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Popup event manager. Handles the popup's entire lifecycle; listens to auth
* events
*/
var AbstractPopupRedirectOperation = /** @class */ (function () {
function AbstractPopupRedirectOperation(auth, filter, resolver, user, bypassAuthState) {
if (bypassAuthState === void 0) { bypassAuthState = false; }
this.auth = auth;
this.resolver = resolver;
this.user = user;
this.bypassAuthState = bypassAuthState;
this.pendingPromise = null;
this.eventManager = null;
this.filter = Array.isArray(filter) ? filter : [filter];
}
AbstractPopupRedirectOperation.prototype.execute = function () {
var _this = this;
return new Promise(function (resolve, reject) { return tslib.__awaiter(_this, void 0, void 0, function () {
var _a, e_1;
return tslib.__generator(this, function (_b) {
switch (_b.label) {
case 0:
this.pendingPromise = { resolve: resolve, reject: reject };
_b.label = 1;
case 1:
_b.trys.push([1, 4, , 5]);
_a = this;
return [4 /*yield*/, this.resolver._initialize(this.auth)];
case 2:
_a.eventManager = _b.sent();
return [4 /*yield*/, this.onExecution()];
case 3:
_b.sent();
this.eventManager.registerConsumer(this);
return [3 /*break*/, 5];
case 4:
e_1 = _b.sent();
this.reject(e_1);
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
}); });
};
AbstractPopupRedirectOperation.prototype.onAuthEvent = function (event) {
return tslib.__awaiter(this, void 0, void 0, function () {
var urlResponse, sessionId, postBody, tenantId, error, type, params, _a, e_2;
return tslib.__generator(this, function (_b) {
switch (_b.label) {
case 0:
urlResponse = event.urlResponse, sessionId = event.sessionId, postBody = event.postBody, tenantId = event.tenantId, error = event.error, type = event.type;
if (error) {
this.reject(error);
return [2 /*return*/];
}
params = {
auth: this.auth,
requestUri: urlResponse,
sessionId: sessionId,
tenantId: tenantId || undefined,
postBody: postBody || undefined,
user: this.user,
bypassAuthState: this.bypassAuthState
};
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
_a = this.resolve;
return [4 /*yield*/, this.getIdpTask(type)(params)];
case 2:
_a.apply(this, [_b.sent()]);
return [3 /*break*/, 4];
case 3:
e_2 = _b.sent();
this.reject(e_2);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
AbstractPopupRedirectOperation.prototype.onError = function (error) {
this.reject(error);
};
AbstractPopupRedirectOperation.prototype.getIdpTask = function (type) {
switch (type) {
case "signInViaPopup" /* SIGN_IN_VIA_POPUP */:
case "signInViaRedirect" /* SIGN_IN_VIA_REDIRECT */:
return _signIn;
case "linkViaPopup" /* LINK_VIA_POPUP */:
case "linkViaRedirect" /* LINK_VIA_REDIRECT */:
return _link;
case "reauthViaPopup" /* REAUTH_VIA_POPUP */:
case "reauthViaRedirect" /* REAUTH_VIA_REDIRECT */:
return _reauth;
default:
index._fail(this.auth, "internal-error" /* INTERNAL_ERROR */);
}
};
AbstractPopupRedirectOperation.prototype.resolve = function (cred) {
index.debugAssert(this.pendingPromise, 'Pending promise was never set');
this.pendingPromise.resolve(cred);
this.unregisterAndCleanUp();
};
AbstractPopupRedirectOperation.prototype.reject = function (error) {
index.debugAssert(this.pendingPromise, 'Pending promise was never set');
this.pendingPromise.reject(error);
this.unregisterAndCleanUp();
};
AbstractPopupRedirectOperation.prototype.unregisterAndCleanUp = function () {
if (this.eventManager) {
this.eventManager.unregisterConsumer(this);
}
this.pendingPromise = null;
this.cleanUp();
};
return AbstractPopupRedirectOperation;
}());
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var PENDING_REDIRECT_KEY = 'pendingRedirect';
// We only get one redirect outcome for any one auth, so just store it
// in here.
var redirectOutcomeMap = new Map();
var RedirectAction = /** @class */ (function (_super) {
tslib.__extends(RedirectAction, _super);
function RedirectAction(auth, resolver, bypassAuthState) {
if (bypassAuthState === void 0) { bypassAuthState = false; }
var _this = _super.call(this, auth, [
"signInViaRedirect" /* SIGN_IN_VIA_REDIRECT */,
"linkViaRedirect" /* LINK_VIA_REDIRECT */,
"reauthViaRedirect" /* REAUTH_VIA_REDIRECT */,
"unknown" /* UNKNOWN */
], resolver, undefined, bypassAuthState) || this;
_this.eventId = null;
return _this;
}
/**
* Override the execute function; if we already have a redirect result, then
* just return it.
*/
RedirectAction.prototype.execute = function () {
return tslib.__awaiter(this, void 0, void 0, function () {
var readyOutcome, hasPendingRedirect, result_1, _a, e_1;
return tslib.__generator(this, function (_b) {
switch (_b.label) {
case 0:
readyOutcome = redirectOutcomeMap.get(this.auth._key());
if (!!readyOutcome) return [3 /*break*/, 8];
_b.label = 1;
case 1:
_b.trys.push([1, 6, , 7]);
return [4 /*yield*/, _getAndClearPendingRedirectStatus(this.resolver, this.auth)];
case 2:
hasPendingRedirect = _b.sent();
if (!hasPendingRedirect) return [3 /*break*/, 4];
return [4 /*yield*/, _super.prototype.execute.call(this)];
case 3:
_a = _b.sent();
return [3 /*break*/, 5];
case 4:
_a = null;
_b.label = 5;
case 5:
result_1 = _a;
readyOutcome = function () { return Promise.resolve(result_1); };
return [3 /*break*/, 7];
case 6:
e_1 = _b.sent();
readyOutcome = function () { return Promise.reject(e_1); };
return [3 /*break*/, 7];
case 7:
redirectOutcomeMap.set(this.auth._key(), readyOutcome);
_b.label = 8;
case 8:
// If we're not bypassing auth state, the ready outcome should be set to
// null.
if (!this.bypassAuthState) {
redirectOutcomeMap.set(this.auth._key(), function () { return Promise.resolve(null); });
}
return [2 /*return*/, readyOutcome()];
}
});
});
};
RedirectAction.prototype.onAuthEvent = function (event) {
return tslib.__awaiter(this, void 0, void 0, function () {
var user;
return tslib.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (event.type === "signInViaRedirect" /* SIGN_IN_VIA_REDIRECT */) {
return [2 /*return*/, _super.prototype.onAuthEvent.call(this, event)];
}
else if (event.type === "unknown" /* UNKNOWN */) {
// This is a sentinel value indicating there's no pending redirect
this.resolve(null);
return [2 /*return*/];
}
if (!event.eventId) return [3 /*break*/, 2];
return [4 /*yield*/, this.auth._redirectUserForId(event.eventId)];
case 1:
user = _a.sent();
if (user) {
this.user = user;
return [2 /*return*/, _super.prototype.onAuthEvent.call(this, event)];
}
else {
this.resolve(null);
}
_a.label = 2;
case 2: return [2 /*return*/];
}
});
});
};
RedirectAction.prototype.onExecution = function () {
return tslib.__awaiter(this, void 0, void 0, function () { return tslib.__generator(this, function (_a) {
return [2 /*return*/];
}); });
};
RedirectAction.prototype.cleanUp = function () { };
return RedirectAction;
}(AbstractPopupRedirectOperation));
function _getAndClearPendingRedirectStatus(resolver, auth) {
return tslib.__awaiter(this, void 0, void 0, function () {
var key, persistence, hasPendingRedirect;
return tslib.__generator(this, function (_a) {
switch (_a.label) {
case 0:
key = pendingRedirectKey(auth);
persistence = resolverPersistence(resolver);
return [4 /*yield*/, persistence._isAvailable()];
case 1:
if (!(_a.sent())) {
return [2 /*return*/, false];
}
return [4 /*yield*/, persistence._get(key)];
case 2:
hasPendingRedirect = (_a.sent()) === 'true';
return [4 /*yield*/, persistence._remove(key)];
case 3:
_a.sent();
return [2 /*return*/, hasPendingRedirect];
}
});
});
}
function _clearRedirectOutcomes() {
redirectOutcomeMap.clear();
}
function _overrideRedirectResult(auth, result) {
redirectOutcomeMap.set(auth._key(), result);
}
function resolverPersistence(resolver) {
return index._getInstance(resolver._redirectPersistence);
}
function pendingRedirectKey(auth) {
return index._persistenceKeyName(PENDING_REDIRECT_KEY, auth.config.apiKey, auth.name);
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function _getRedirectResult(auth, resolverExtern, bypassAuthState) {
if (bypassAuthState === void 0) { bypassAuthState = false; }
return tslib.__awaiter(this, void 0, void 0, function () {
var authInternal, resolver, action, result;
return tslib.__generator(this, function (_a) {
switch (_a.label) {
case 0:
authInternal = index._castAuth(auth);
resolver = _withDefaultResolver(authInternal, resolverExtern);
action = new RedirectAction(authInternal, resolver, bypassAuthState);
return [4 /*yield*/, action.execute()];
case 1:
result = _a.sent();
if (!(result && !bypassAuthState)) return [3 /*break*/, 4];
delete result.user._redirectEventId;
return [4 /*yield*/, authInternal._persistUserIfCurrent(result.user)];
case 2:
_a.sent();
return [4 /*yield*/, authInternal._setRedirectUser(null, resolverExtern)];
case 3:
_a.sent();
_a.label = 4;
case 4: return [2 /*return*/, result];
}
});
});
}
var STORAGE_AVAILABLE_KEY = '__sak';
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// There are two different browser persistence types: local and session.
// Both have the same implementation but use a different underlying storage
// object.
var BrowserPersistenceClass = /** @class */ (function () {
function BrowserPersistenceClass(storageRetriever, type) {
this.storageRetriever = storageRetriever;
this.type = type;
}
BrowserPersistenceClass.prototype._isAvailable = function () {
try {
if (!this.storage) {
return Promise.resolve(false);
}
this.storage.setItem(STORAGE_AVAILABLE_KEY, '1');
this.storage.removeItem(STORAGE_AVAILABLE_KEY);
return Promise.resolve(true);
}
catch (_a) {
return Promise.resolve(false);
}
};
BrowserPersistenceClass.prototype._set = function (key, value) {
this.storage.setItem(key, JSON.stringify(value));
return Promise.resolve();
};
BrowserPersistenceClass.prototype._get = function (key) {
var json = this.storage.getItem(key);
return Promise.resolve(json ? JSON.parse(json) : null);
};
BrowserPersistenceClass.prototype._remove = function (key) {
this.storage.removeItem(key);
return Promise.resolve();
};
Object.defineProperty(BrowserPersistenceClass.prototype, "storage", {
get: function () {
return this.storageRetriever();
},
enumerable: false,
configurable: true
});
return BrowserPersistenceClass;
}());
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var BrowserSessionPersistence = /** @class */ (function (_super) {
tslib.__extends(BrowserSessionPersistence, _super);
function BrowserSessionPersistence() {
return _super.call(this, function () { return window.sessionStorage; }, "SESSION" /* SESSION */) || this;
}
BrowserSessionPersistence.prototype._addListener = function (_key, _listener) {
// Listeners are not supported for session storage since it cannot be shared across windows
return;
};
BrowserSessionPersistence.prototype._removeListener = function (_key, _listener) {
// Listeners are not supported for session storage since it cannot be shared across windows
return;
};
BrowserSessionPersistence.type = 'SESSION';
return BrowserSessionPersistence;
}(BrowserPersistenceClass));
/**
* An implementation of {@link Persistence} of `SESSION` using `sessionStorage`
* for the underlying storage.
*
* @public
*/
var browserSessionPersistence = BrowserSessionPersistence;
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* URL for Authentication widget which will initiate the OAuth handshake
*
* @internal
*/
var WIDGET_PATH = '__/auth/handler';
/**
* URL for emulated environment
*
* @internal
*/
var EMULATOR_WIDGET_PATH = 'emulator/auth/handler';
function _getRedirectUrl(auth, provider, authType, redirectUrl, eventId, additionalParams) {
index._assert(auth.config.authDomain, auth, "auth-domain-config-required" /* MISSING_AUTH_DOMAIN */);
index._assert(auth.config.apiKey, auth, "invalid-api-key" /* INVALID_API_KEY */);
var params = {
apiKey: auth.config.apiKey,
appName: auth.name,
authType: authType,
redirectUrl: redirectUrl,
v: app.SDK_VERSION,
eventId: eventId
};
if (provider instanceof index.FederatedAuthProvider) {
provider.setDefaultLanguage(auth.languageCode);
params.providerId = provider.providerId || '';
if (!util.isEmpty(provider.getCustomParameters())) {
params.customParameters = JSON.stringify(provider.getCustomParameters());
}
// TODO set additionalParams from the provider as well?
for (var _i = 0, _a = Object.entries(additionalParams || {}); _i < _a.length; _i++) {
var _b = _a[_i], key = _b[0], value = _b[1];
params[key] = value;
}
}
if (provider instanceof index.BaseOAuthProvider) {
var scopes = provider.getScopes().filter(function (scope) { return scope !== ''; });
if (scopes.length > 0) {
params.scopes = scopes.join(',');
}
}
if (auth.tenantId) {
params.tid = auth.tenantId;
}
// TODO: maybe set eid as endipointId
// TODO: maybe set fw as Frameworks.join(",")
var paramsDict = params;
for (var _c = 0, _d = Object.keys(paramsDict); _c < _d.length; _c++) {
var key = _d[_c];
if (paramsDict[key] === undefined) {
delete paramsDict[key];
}
}
return getHandlerBase(auth) + "?" + util.querystring(paramsDict).slice(1);
}
function getHandlerBase(_a) {
var config = _a.config;
if (!config.emulator) {
return "https://" + config.authDomain + "/" + WIDGET_PATH;
}
return index._emulatorUrl(config, EMULATOR_WIDGET_PATH);
}
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function _cordovaWindow() {
return window;
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function _getProjectConfig(auth, request) {
if (request === void 0) { request = {}; }
return tslib.__awaiter(this, void 0, void 0, function () {
return tslib.__generator(this, function (_a) {
return [2 /*return*/, index._performApiRequest(auth, "GET" /* GET */, "/v1/projects" /* GET_PROJECT_CONFIG */, request)];
});
});
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* How long to wait after the app comes back into focus before concluding that
* the user closed the sign in tab.
*/
var REDIRECT_TIMEOUT_MS = 2000;
/**
* Generates the URL for the OAuth handler.
*/
function _generateHandlerUrl(auth, event, provider) {
var _a;
return tslib.__awaiter(this, void 0, void 0, function () {
var BuildInfo, sessionDigest, additionalParams;
return tslib.__generator(this, function (_b) {
switch (_b.label) {
case 0:
BuildInfo = _cordovaWindow().BuildInfo;
index.debugAssert(event.sessionId, 'AuthEvent did not contain a session ID');
return [4 /*yield*/, computeSha256(event.sessionId)];
case 1:
sessionDigest = _b.sent();
additionalParams = {};
if (index._isIOS()) {
// iOS app identifier
additionalParams['ibi'] = BuildInfo.packageName;
}
else if (index._isAndroid()) {
// Android app identifier
additionalParams['apn'] = BuildInfo.packageName;
}
else {
index._fail(auth, "operation-not-supported-in-this-environment" /* OPERATION_NOT_SUPPORTED */);
}
// Add the display name if available
if (BuildInfo.displayName) {
additionalParams['appDisplayName'] = BuildInfo.displayName;
}
// Attached the hashed session ID
additionalParams['sessionId'] = sessionDigest;
return [2 /*return*/, _getRedirectUrl(auth, provider, event.type, undefined, (_a = event.eventId) !== null && _a !== void 0 ? _a : undefined, additionalParams)];
}
});
});
}
/**
* Validates that this app is valid for this project configuration
*/
function _validateOrigin(auth) {
return tslib.__awaiter(this, void 0, void 0, function () {
var BuildInfo, request;
return tslib.__generator(this, function (_a) {
switch (_a.label) {
case 0:
BuildInfo = _cordovaWindow().BuildInfo;
request = {};
if (index._isIOS()) {
request.iosBundleId = BuildInfo.packageName;
}
else if (index._isAndroid()) {
request.androidPackageName = BuildInfo.packageName;
}
else {
index._fail(auth, "operation-not-supported-in-this-environment" /* OPERATION_NOT_SUPPORTED */);
}
// Will fail automatically if package name is not authorized
return [4 /*yield*/, _getProjectConfig(auth, request)];
case 1:
// Will fail automatically if package name is not authorized
_a.sent();
return [2 /*return*/];
}
});
});
}
function _performRedirect(handlerUrl) {
// Get the cordova plugins
var cordova = _cordovaWindow().cordova;
return new Promise(function (resolve) {
cordova.plugins.browsertab.isAvailable(function (browserTabIsAvailable) {
var iabRef = null;
if (browserTabIsAvailable) {
cordova.plugins.browsertab.openUrl(handlerUrl);
}
else {
// TODO: Return the inappbrowser ref that's returned from the open call
iabRef = cordova.InAppBrowser.open(handlerUrl, index._isIOS7Or8() ? '_blank' : '_system', 'location=yes');
}
resolve(iabRef);
});
});
}
/**
* This function waits for app activity to be seen before resolving. It does
* this by attaching listeners to various dom events. Once the app is determined
* to be visible, this promise resolves. AFTER that resolution, the listeners
* are detached and any browser tabs left open will be closed.
*/
function _waitForAppResume(auth, eventListener, iabRef) {
return tslib.__awaiter(this, void 0, void 0, function () {
var cordova, cleanup;
return tslib.__generator(this, function (_a) {
switch (_a.label) {
case 0:
cordova = _cordovaWindow().cordova;
cleanup = function () { };
_a.label = 1;
case 1:
_a.trys.push([1, , 3, 4]);
return [4 /*yield*/, new Promise(function (resolve, reject) {
var onCloseTimer = null;
// DEFINE ALL THE CALLBACKS =====
function authEventSeen() {
var _a;
// Auth event was detected. Resolve this promise and close the extra
// window if it's still open.
resolve();
var closeBrowserTab = (_a = cordova.plugins.browsertab) === null || _a === void 0 ? void 0 : _a.close;
if (typeof closeBrowserTab === 'function') {
closeBrowserTab();
}
// Close inappbrowser emebedded webview in iOS7 and 8 case if still
// open.
if (typeof (iabRef === null || iabRef === void 0 ? void 0 : iabRef.close) === 'function') {
iabRef.close();
}
}
function resumed() {
if (onCloseTimer) {
// This code already ran; do not rerun.
return;
}
onCloseTimer = window.setTimeout(function () {
// Wait two seeconds after resume then reject.
reject(index._createError(auth, "redirect-cancelled-by-user" /* REDIRECT_CANCELLED_BY_USER */));
}, REDIRECT_TIMEOUT_MS);
}
function visibilityChanged() {
if ((document === null || document === void 0 ? void 0 : document.visibilityState) === 'visible') {
resumed();
}
}
// ATTACH ALL THE LISTENERS =====
// Listen for the auth event
eventListener.addPassiveListener(authEventSeen);
// Listen for resume and visibility events
document.addEventListener('resume', resumed, false);
if (index._isAndroid()) {
document.addEventListener('visibilitychange', visibilityChanged, false);
}
// SETUP THE CLEANUP FUNCTION =====
cleanup = function () {
eventListener.removePassiveListener(authEventSeen);
document.removeEventListener('resume', resumed, false);
document.removeEventListener('visibilitychange', visibilityChanged, false);
if (onCloseTimer) {
window.clearTimeout(onCloseTimer);
}
};
})];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
cleanup();
return [7 /*endfinally*/];
case 4: return [2 /*return*/];
}
});
});
}
/**
* Checks the configuration of the Cordova environment. This has no side effect
* if the configuration is correct; otherwise it throws an error with the
* missing plugin.
*/
function _checkCordovaConfiguration(auth) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
var win = _cordovaWindow();
// Check all dependencies installed.
// https://github.com/nordnet/cordova-universal-links-plugin
// Note that cordova-universal-links-plugin has been abandoned.
// A fork with latest fixes is available at:
// https://www.npmjs.com/package/cordova-universal-links-plugin-fix
index._assert(typeof ((_a = win === null || win === void 0 ? void 0 : win.universalLinks) === null || _a === void 0 ? void 0 : _a.subscribe) === 'function', auth, "invalid-cordova-configuration" /* INVALID_CORDOVA_CONFIGURATION */, {
missingPlugin: 'cordova-universal-links-plugin-fix'
});
// https://www.npmjs.com/package/cordova-plugin-buildinfo
index._assert(typeof ((_b = win === null || win === void 0 ? void 0 : win.BuildInfo) === null || _b === void 0 ? void 0 : _b.packageName) !== 'undefined', auth, "invalid-cordova-configuration" /* INVALID_CORDOVA_CONFIGURATION */, {
missingPlugin: 'cordova-plugin-buildInfo'
});
// https://github.com/google/cordova-plugin-browsertab
index._assert(typeof ((_e = (_d = (_c = win === null || win === void 0 ? void 0 : win.cordova) === null || _c === void 0 ? void 0 : _c.plugins) === null || _d === void 0 ? void 0 : _d.browsertab) === null || _e === void 0 ? void 0 : _e.openUrl) === 'function', auth, "invalid-cordova-configuration" /* INVALID_CORDOVA_CONFIGURATION */, {
missingPlugin: 'cordova-plugin-browsertab'
});
index._assert(typeof ((_h = (_g = (_f = win === null || win === void 0 ? void 0 : win.cordova) === null || _f === void 0 ? void 0 : _f.plugins) === null || _g === void 0 ? void 0 : _g.browsertab) === null || _h === void 0 ? void 0 : _h.isAvailable) === 'function', auth, "invalid-cordova-configuration" /* INVALID_CORDOVA_CONFIGURATION */, {
missingPlugin: 'cordova-plugin-browsertab'
});
// https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/
index._assert(typeof ((_k = (_j = win === null || win === void 0 ? void 0 : win.cordova) === null || _j === void 0 ? void 0 : _j.InAppBrowser) === null || _k === void 0 ? void 0 : _k.open) === 'function', auth, "invalid-cordova-configuration" /* INVALID_CORDOVA_CONFIGURATION */, {
missingPlugin: 'cordova-plugin-inappbrowser'
});
}
/**
* Computes the SHA-256 of a session ID. The SubtleCrypto interface is only
* available in "secure" contexts, which covers Cordova (which is served on a file
* protocol).
*/
function computeSha256(sessionId) {
return tslib.__awaiter(this, void 0, void 0, function () {
var bytes, buf, arr;
return tslib.__generator(this, function (_a) {
switch (_a.label) {
case 0:
bytes = stringToArrayBuffer(sessionId);
return [4 /*yield*/, crypto.subtle.digest('SHA-256', bytes)];
case 1:
buf = _a.sent();
arr = Array.from(new Uint8Array(buf));
return [2 /*return*/, arr.map(function (num) { return num.toString(16).padStart(2, '0'); }).join('')];
}
});
});
}
function stringToArrayBuffer(str) {
// This function is only meant to deal with an ASCII charset and makes
// certain simplifying assumptions.
index.debugAssert(/[0-9a-zA-Z]+/.test(str), 'Can only convert alpha-numeric strings');
if (typeof TextEncoder !== 'undefined') {
return new TextEncoder().encode(str);
}
var buff = new ArrayBuffer(str.length);
var view = new Uint8Array(buff);
for (var i = 0; i < str.length; i++) {
view[i] = str.charCodeAt(i);
}
return view;
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// The amount of time to store the UIDs of seen events; this is
// set to 10 min by default
var EVENT_DUPLICATION_CACHE_DURATION_MS = 10 * 60 * 1000;
var AuthEventManager = /** @class */ (function () {
function AuthEventManager(auth) {
this.auth = auth;
this.cachedEventUids = new Set();
this.consumers = new Set();
this.queuedRedirectEvent = null;
this.hasHandledPotentialRedirect = false;
this.lastProcessedEventTime = Date.now();
}
AuthEventManager.prototype.registerConsumer = function (authEventConsumer) {
this.consumers.add(authEventConsumer);
if (this.queuedRedirectEvent &&
this.isEventForConsumer(this.queuedRedirectEvent, authEventConsumer)) {
this.sendToConsumer(this.queuedRedirectEvent, authEventConsumer);
this.saveEventToCache(this.queuedRedirectEvent);
this.queuedRedirectEvent = null;
}
};
AuthEventManager.prototype.unregisterConsumer = function (authEventConsumer) {
this.consumers.delete(authEventConsumer);
};
AuthEventManager.prototype.onEvent = function (event) {
var _this = this;
// Check if the event has already been handled
if (this.hasEventBeenHandled(event)) {
return false;
}
var handled = false;
this.consumers.forEach(function (consumer) {
if (_this.isEventForConsumer(event, consumer)) {
handled = true;
_this.sendToConsumer(event, consumer);
_this.saveEventToCache(event);
}
});
if (this.hasHandledPotentialRedirect || !isRedirectEvent(event)) {
// If we've already seen a redirect before, or this is a popup event,
// bail now
return handled;
}
this.hasHandledPotentialRedirect = true;
// If the redirect wasn't handled, hang on to it
if (!handled) {
this.queuedRedirectEvent = event;
handled = true;
}
return handled;
};
AuthEventManager.prototype.sendToConsumer = function (event, consumer) {
var _a;
if (event.error && !isNullRedirectEvent(event)) {
var code = ((_a = event.error.code) === null || _a === void 0 ? void 0 : _a.split('auth/')[1]) ||
"internal-error" /* INTERNAL_ERROR */;
consumer.onError(index._createError(this.auth, code));
}
else {
consumer.onAuthEvent(event);
}
};
AuthEventManager.prototype.isEventForConsumer = function (event, consumer) {
var eventIdMatches = consumer.eventId === null ||
(!!event.eventId && event.eventId === consumer.eventId);
return consumer.filter.includes(event.type) && eventIdMatches;
};
AuthEventManager.prototype.hasEventBeenHandled = function (event) {
if (Date.now() - this.lastProcessedEventTime >=
EVENT_DUPLICATION_CACHE_DURATION_MS) {
this.cachedEventUids.clear();
}
return this.cachedEventUids.has(eventUid(event));
};
AuthEventManager.prototype.saveEventToCache = function (event) {
this.cachedEventUids.add(eventUid(event));
this.lastProcessedEventTime = Date.now();
};
return AuthEventManager;
}());
function eventUid(e) {
return [e.type, e.eventId, e.sessionId, e.tenantId].filter(function (v) { return v; }).join('-');
}
function isNullRedirectEvent(_a) {
var type = _a.type, error = _a.error;
return (type === "unknown" /* UNKNOWN */ &&
(error === null || error === void 0 ? void 0 : error.code) === "auth/" + "no-auth-event" /* NO_AUTH_EVENT */);
}
function isRedirectEvent(event) {
switch (event.type) {
case "signInViaRedirect" /* SIGN_IN_VIA_REDIRECT */:
case "linkViaRedirect" /* LINK_VIA_REDIRECT */:
case "reauthViaRedirect" /* REAUTH_VIA_REDIRECT */:
return true;
case "unknown" /* UNKNOWN */:
return isNullRedirectEvent(event);
default:
return false;
}
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function _iframeCannotSyncWebStorage() {
var ua = util.getUA();
return index._isSafari(ua) || index._isIOS(ua);
}
// The polling period in case events are not supported
var _POLLING_INTERVAL_MS = 1000;
// The IE 10 localStorage cross tab synchronization delay in milliseconds
var IE10_LOCAL_STORAGE_SYNC_DELAY = 10;
var BrowserLocalPersistence = /** @class */ (function (_super) {
tslib.__extends(BrowserLocalPersistence, _super);
function BrowserLocalPersistence() {
var _this = _super.call(this, function () { return window.localStorage; }, "LOCAL" /* LOCAL */) || this;
_this.boundEventHandler = function (event, poll) { return _this.onStorageEvent(event, poll); };
_this.listeners = {};
_this.localCache = {};
// setTimeout return value is platform specific
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_this.pollTimer = null;
// Safari or iOS browser and embedded in an iframe.
_this.safariLocalStorageNotSynced = _iframeCannotSyncWebStorage() && index._isIframe();
// Whether to use polling instead of depending on window events
_this.fallbackToPolling = index._isMobileBrowser();
_this._shouldAllowMigration = true;
return _this;
}
BrowserLocalPersistence.prototype.forAllChangedKeys = function (cb) {
// Check all keys with listeners on them.
for (var _i = 0, _a = Object.keys(this.listeners); _i < _a.length; _i++) {
var key = _a[_i];
// Get value from localStorage.
var newValue = this.storage.getItem(key);
var oldValue = this.localCache[key];
// If local map value does not match, trigger listener with storage event.
// Differentiate this simulated event from the real storage event.
if (newValue !== oldValue) {
cb(key, oldValue, newValue);
}
}
};
BrowserLocalPersistence.prototype.onSt