@firebase/auth
Version:
The Firebase Authenticaton component of the Firebase JS SDK.
1,112 lines (1,103 loc) • 85.5 kB
JavaScript
import { af as _performApiRequest, ag as _addTidIfNecessary, ah as _createError, ai as _assert, aj as Delay, ak as _window, al as _isHttpOrHttps, am as _isWorker, an as _castAuth, J as signInWithCredential, ao as sendPhoneVerificationCode, ap as startEnrollPhoneMfa, K as linkWithCredential, aq as _assertLinkedStatus, L as reauthenticateWithCredential, ar as _link, x as PhoneAuthCredential, as as debugAssert, at as _generateEventId, au as AbstractPopupRedirectOperation, av as _assertInstanceOf, aw as _withDefaultResolver, ax as FederatedAuthProvider, ay as _fail, az as _getProjectConfig, aA as _getCurrentUrl, aB as _emulatorUrl, aC as _isChromeIOS, aD as _isFirefox, aE as _isIOSStandalone, aF as _isMobileBrowser, aG as _isSafari, aH as _isIOS, f as browserSessionPersistence, aI as _getRedirectResult, aJ as _overrideRedirectResult, aK as _getRedirectUrl, aL as _setWindowLocation, aM as AuthEventManager, aN as debugFail, aO as finalizeEnrollPhoneMfa, r as registerAuth, i as initializeAuth, c as indexedDBLocalPersistence, e as browserLocalPersistence } from './popup_redirect-212c98e6.js';
export { A as ActionCodeOperation, a3 as ActionCodeURL, v as AuthCredential, q as AuthErrorCodes, aS as AuthImpl, E as EmailAuthCredential, z as EmailAuthProvider, B as FacebookAuthProvider, F as FactorId, aU as FetchProvider, C as GithubAuthProvider, G as GoogleAuthProvider, w as OAuthCredential, D as OAuthProvider, O as OperationType, x as PhoneAuthCredential, P as ProviderId, aV as SAMLAuthCredential, H as SAMLAuthProvider, S as SignInMethod, T as TwitterAuthProvider, aQ as UserImpl, ai as _assert, an as _castAuth, ay as _fail, at as _generateEventId, aT as _getClientVersion, aR as _getInstance, aI as _getRedirectResult, aJ as _overrideRedirectResult, aP as _persistenceKeyName, R as applyActionCode, h as beforeAuthStateChanged, e as browserLocalPersistence, f as browserSessionPersistence, U as checkActionCode, Q as confirmPasswordReset, t as connectAuthEmulator, d as cordovaPopupRedirectResolver, W as createUserWithEmailAndPassword, n as debugErrorMap, m as deleteUser, a0 as fetchSignInMethodsForEmail, ab as getAdditionalUserInfo, a8 as getIdToken, a9 as getIdTokenResult, ad as getMultiFactorResolver, g as getRedirectResult, y as inMemoryPersistence, c as indexedDBLocalPersistence, i as initializeAuth, Z as isSignInWithEmailLink, K as linkWithCredential, aX as linkWithRedirect, ae as multiFactor, j as onAuthStateChanged, o as onIdTokenChanged, a4 as parseActionCodeURL, p as prodErrorMap, L as reauthenticateWithCredential, aY as reauthenticateWithRedirect, ac as reload, a1 as sendEmailVerification, N as sendPasswordResetEmail, Y as sendSignInLinkToEmail, s as setPersistence, I as signInAnonymously, J as signInWithCredential, M as signInWithCustomToken, X as signInWithEmailAndPassword, $ as signInWithEmailLink, aW as signInWithRedirect, l as signOut, aa as unlink, k as updateCurrentUser, a6 as updateEmail, a7 as updatePassword, a5 as updateProfile, u as useDeviceLanguage, a2 as verifyBeforeUpdateEmail, V as verifyPasswordResetCode } from './popup_redirect-212c98e6.js';
import { __awaiter, __generator, __assign, __extends, __spreadArray } from 'tslib';
import { querystring, getModularInstance, getUA } from '@firebase/util';
import { SDK_VERSION, getApp, _getProvider } from '@firebase/app';
import '@firebase/component';
import '@firebase/logger';
/**
* @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 startSignInPhoneMfa(auth, request) {
return _performApiRequest(auth, "POST" /* POST */, "/v2/accounts/mfaSignIn:start" /* START_PHONE_MFA_SIGN_IN */, _addTidIfNecessary(auth, request));
}
function finalizeSignInPhoneMfa(auth, request) {
return _performApiRequest(auth, "POST" /* POST */, "/v2/accounts/mfaSignIn:finalize" /* FINALIZE_PHONE_MFA_SIGN_IN */, _addTidIfNecessary(auth, 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.
*/
function getRecaptchaParams(auth) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, _performApiRequest(auth, "GET" /* GET */, "/v1/recaptchaParams" /* GET_RECAPTCHA_PARAM */)];
case 1: return [2 /*return*/, ((_a.sent()).recaptchaSiteKey || '')];
}
});
});
}
/**
* @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 getScriptParentElement() {
var _a, _b;
return (_b = (_a = document.getElementsByTagName('head')) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : document;
}
function _loadJS(url) {
// TODO: consider adding timeout support & cancellation
return new Promise(function (resolve, reject) {
var el = document.createElement('script');
el.setAttribute('src', url);
el.onload = resolve;
el.onerror = function (e) {
var error = _createError("internal-error" /* INTERNAL_ERROR */);
error.customData = e;
reject(error);
};
el.type = 'text/javascript';
el.charset = 'UTF-8';
getScriptParentElement().appendChild(el);
});
}
function _generateCallbackName(prefix) {
return "__" + prefix + Math.floor(Math.random() * 1000000);
}
/**
* @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 _SOLVE_TIME_MS = 500;
var _EXPIRATION_TIME_MS = 60000;
var _WIDGET_ID_START = 1000000000000;
var MockReCaptcha = /** @class */ (function () {
function MockReCaptcha(auth) {
this.auth = auth;
this.counter = _WIDGET_ID_START;
this._widgets = new Map();
}
MockReCaptcha.prototype.render = function (container, parameters) {
var id = this.counter;
this._widgets.set(id, new MockWidget(container, this.auth.name, parameters || {}));
this.counter++;
return id;
};
MockReCaptcha.prototype.reset = function (optWidgetId) {
var _a;
var id = optWidgetId || _WIDGET_ID_START;
void ((_a = this._widgets.get(id)) === null || _a === void 0 ? void 0 : _a.delete());
this._widgets.delete(id);
};
MockReCaptcha.prototype.getResponse = function (optWidgetId) {
var _a;
var id = optWidgetId || _WIDGET_ID_START;
return ((_a = this._widgets.get(id)) === null || _a === void 0 ? void 0 : _a.getResponse()) || '';
};
MockReCaptcha.prototype.execute = function (optWidgetId) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var id;
return __generator(this, function (_b) {
id = optWidgetId || _WIDGET_ID_START;
void ((_a = this._widgets.get(id)) === null || _a === void 0 ? void 0 : _a.execute());
return [2 /*return*/, ''];
});
});
};
return MockReCaptcha;
}());
var MockWidget = /** @class */ (function () {
function MockWidget(containerOrId, appName, params) {
var _this = this;
this.params = params;
this.timerId = null;
this.deleted = false;
this.responseToken = null;
this.clickHandler = function () {
_this.execute();
};
var container = typeof containerOrId === 'string'
? document.getElementById(containerOrId)
: containerOrId;
_assert(container, "argument-error" /* ARGUMENT_ERROR */, { appName: appName });
this.container = container;
this.isVisible = this.params.size !== 'invisible';
if (this.isVisible) {
this.execute();
}
else {
this.container.addEventListener('click', this.clickHandler);
}
}
MockWidget.prototype.getResponse = function () {
this.checkIfDeleted();
return this.responseToken;
};
MockWidget.prototype.delete = function () {
this.checkIfDeleted();
this.deleted = true;
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
this.container.removeEventListener('click', this.clickHandler);
};
MockWidget.prototype.execute = function () {
var _this = this;
this.checkIfDeleted();
if (this.timerId) {
return;
}
this.timerId = window.setTimeout(function () {
_this.responseToken = generateRandomAlphaNumericString(50);
var _a = _this.params, callback = _a.callback, expiredCallback = _a["expired-callback"];
if (callback) {
try {
callback(_this.responseToken);
}
catch (e) { }
}
_this.timerId = window.setTimeout(function () {
_this.timerId = null;
_this.responseToken = null;
if (expiredCallback) {
try {
expiredCallback();
}
catch (e) { }
}
if (_this.isVisible) {
_this.execute();
}
}, _EXPIRATION_TIME_MS);
}, _SOLVE_TIME_MS);
};
MockWidget.prototype.checkIfDeleted = function () {
if (this.deleted) {
throw new Error('reCAPTCHA mock was already deleted!');
}
};
return MockWidget;
}());
function generateRandomAlphaNumericString(len) {
var chars = [];
var allowedChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
for (var i = 0; i < len; i++) {
chars.push(allowedChars.charAt(Math.floor(Math.random() * allowedChars.length)));
}
return chars.join('');
}
/**
* @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.
*/
// ReCaptcha will load using the same callback, so the callback function needs
// to be kept around
var _JSLOAD_CALLBACK = _generateCallbackName('rcb');
var NETWORK_TIMEOUT_DELAY = new Delay(30000, 60000);
var RECAPTCHA_BASE = 'https://www.google.com/recaptcha/api.js?';
/**
* Loader for the GReCaptcha library. There should only ever be one of this.
*/
var ReCaptchaLoaderImpl = /** @class */ (function () {
function ReCaptchaLoaderImpl() {
this.hostLanguage = '';
this.counter = 0;
this.librarySeparatelyLoaded = !!_window().grecaptcha;
}
ReCaptchaLoaderImpl.prototype.load = function (auth, hl) {
var _this = this;
if (hl === void 0) { hl = ''; }
_assert(isHostLanguageValid(hl), auth, "argument-error" /* ARGUMENT_ERROR */);
if (this.shouldResolveImmediately(hl)) {
return Promise.resolve(_window().grecaptcha);
}
return new Promise(function (resolve, reject) {
var networkTimeout = _window().setTimeout(function () {
reject(_createError(auth, "network-request-failed" /* NETWORK_REQUEST_FAILED */));
}, NETWORK_TIMEOUT_DELAY.get());
_window()[_JSLOAD_CALLBACK] = function () {
_window().clearTimeout(networkTimeout);
delete _window()[_JSLOAD_CALLBACK];
var recaptcha = _window().grecaptcha;
if (!recaptcha) {
reject(_createError(auth, "internal-error" /* INTERNAL_ERROR */));
return;
}
// Wrap the greptcha render function so that we know if the developer has
// called it separately
var render = recaptcha.render;
recaptcha.render = function (container, params) {
var widgetId = render(container, params);
_this.counter++;
return widgetId;
};
_this.hostLanguage = hl;
resolve(recaptcha);
};
var url = RECAPTCHA_BASE + "?" + querystring({
onload: _JSLOAD_CALLBACK,
render: 'explicit',
hl: hl
});
_loadJS(url).catch(function () {
clearTimeout(networkTimeout);
reject(_createError(auth, "internal-error" /* INTERNAL_ERROR */));
});
});
};
ReCaptchaLoaderImpl.prototype.clearedOneInstance = function () {
this.counter--;
};
ReCaptchaLoaderImpl.prototype.shouldResolveImmediately = function (hl) {
// We can resolve immediately if:
// • grecaptcha is already defined AND (
// 1. the requested language codes are the same OR
// 2. there exists already a ReCaptcha on the page
// 3. the library was already loaded by the app
// In cases (2) and (3), we _can't_ reload as it would break the recaptchas
// that are already in the page
return (!!_window().grecaptcha &&
(hl === this.hostLanguage ||
this.counter > 0 ||
this.librarySeparatelyLoaded));
};
return ReCaptchaLoaderImpl;
}());
function isHostLanguageValid(hl) {
return hl.length <= 6 && /^\s*[a-zA-Z0-9\-]*\s*$/.test(hl);
}
var MockReCaptchaLoaderImpl = /** @class */ (function () {
function MockReCaptchaLoaderImpl() {
}
MockReCaptchaLoaderImpl.prototype.load = function (auth) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, new MockReCaptcha(auth)];
});
});
};
MockReCaptchaLoaderImpl.prototype.clearedOneInstance = function () { };
return MockReCaptchaLoaderImpl;
}());
/**
* @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 RECAPTCHA_VERIFIER_TYPE = 'recaptcha';
var DEFAULT_PARAMS = {
theme: 'light',
type: 'image'
};
/**
* An {@link https://www.google.com/recaptcha/ | reCAPTCHA}-based application verifier.
*
* @public
*/
var RecaptchaVerifier = /** @class */ (function () {
/**
*
* @param containerOrId - The reCAPTCHA container parameter.
*
* @remarks
* This has different meaning depending on whether the reCAPTCHA is hidden or visible. For a
* visible reCAPTCHA the container must be empty. If a string is used, it has to correspond to
* an element ID. The corresponding element must also must be in the DOM at the time of
* initialization.
*
* @param parameters - The optional reCAPTCHA parameters.
*
* @remarks
* Check the reCAPTCHA docs for a comprehensive list. All parameters are accepted except for
* the sitekey. Firebase Auth backend provisions a reCAPTCHA for each project and will
* configure this upon rendering. For an invisible reCAPTCHA, a size key must have the value
* 'invisible'.
*
* @param authExtern - The corresponding Firebase {@link Auth} instance.
*
* @remarks
* If none is provided, the default Firebase {@link Auth} instance is used. A Firebase {@link Auth} instance
* must be initialized with an API key, otherwise an error will be thrown.
*/
function RecaptchaVerifier(containerOrId, parameters, authExtern) {
if (parameters === void 0) { parameters = __assign({}, DEFAULT_PARAMS); }
this.parameters = parameters;
/**
* The application verifier type.
*
* @remarks
* For a reCAPTCHA verifier, this is 'recaptcha'.
*/
this.type = RECAPTCHA_VERIFIER_TYPE;
this.destroyed = false;
this.widgetId = null;
this.tokenChangeListeners = new Set();
this.renderPromise = null;
this.recaptcha = null;
this.auth = _castAuth(authExtern);
this.isInvisible = this.parameters.size === 'invisible';
_assert(typeof document !== 'undefined', this.auth, "operation-not-supported-in-this-environment" /* OPERATION_NOT_SUPPORTED */);
var container = typeof containerOrId === 'string'
? document.getElementById(containerOrId)
: containerOrId;
_assert(container, this.auth, "argument-error" /* ARGUMENT_ERROR */);
this.container = container;
this.parameters.callback = this.makeTokenCallback(this.parameters.callback);
this._recaptchaLoader = this.auth.settings.appVerificationDisabledForTesting
? new MockReCaptchaLoaderImpl()
: new ReCaptchaLoaderImpl();
this.validateStartingState();
// TODO: Figure out if sdk version is needed
}
/**
* Waits for the user to solve the reCAPTCHA and resolves with the reCAPTCHA token.
*
* @returns A Promise for the reCAPTCHA token.
*/
RecaptchaVerifier.prototype.verify = function () {
return __awaiter(this, void 0, void 0, function () {
var id, recaptcha, response;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.assertNotDestroyed();
return [4 /*yield*/, this.render()];
case 1:
id = _a.sent();
recaptcha = this.getAssertedRecaptcha();
response = recaptcha.getResponse(id);
if (response) {
return [2 /*return*/, response];
}
return [2 /*return*/, new Promise(function (resolve) {
var tokenChange = function (token) {
if (!token) {
return; // Ignore token expirations.
}
_this.tokenChangeListeners.delete(tokenChange);
resolve(token);
};
_this.tokenChangeListeners.add(tokenChange);
if (_this.isInvisible) {
recaptcha.execute(id);
}
})];
}
});
});
};
/**
* Renders the reCAPTCHA widget on the page.
*
* @returns A Promise that resolves with the reCAPTCHA widget ID.
*/
RecaptchaVerifier.prototype.render = function () {
var _this = this;
try {
this.assertNotDestroyed();
}
catch (e) {
// This method returns a promise. Since it's not async (we want to return the
// _same_ promise if rendering is still occurring), the API surface should
// reject with the error rather than just throw
return Promise.reject(e);
}
if (this.renderPromise) {
return this.renderPromise;
}
this.renderPromise = this.makeRenderPromise().catch(function (e) {
_this.renderPromise = null;
throw e;
});
return this.renderPromise;
};
/** @internal */
RecaptchaVerifier.prototype._reset = function () {
this.assertNotDestroyed();
if (this.widgetId !== null) {
this.getAssertedRecaptcha().reset(this.widgetId);
}
};
/**
* Clears the reCAPTCHA widget from the page and destroys the instance.
*/
RecaptchaVerifier.prototype.clear = function () {
var _this = this;
this.assertNotDestroyed();
this.destroyed = true;
this._recaptchaLoader.clearedOneInstance();
if (!this.isInvisible) {
this.container.childNodes.forEach(function (node) {
_this.container.removeChild(node);
});
}
};
RecaptchaVerifier.prototype.validateStartingState = function () {
_assert(!this.parameters.sitekey, this.auth, "argument-error" /* ARGUMENT_ERROR */);
_assert(this.isInvisible || !this.container.hasChildNodes(), this.auth, "argument-error" /* ARGUMENT_ERROR */);
_assert(typeof document !== 'undefined', this.auth, "operation-not-supported-in-this-environment" /* OPERATION_NOT_SUPPORTED */);
};
RecaptchaVerifier.prototype.makeTokenCallback = function (existing) {
var _this = this;
return function (token) {
_this.tokenChangeListeners.forEach(function (listener) { return listener(token); });
if (typeof existing === 'function') {
existing(token);
}
else if (typeof existing === 'string') {
var globalFunc = _window()[existing];
if (typeof globalFunc === 'function') {
globalFunc(token);
}
}
};
};
RecaptchaVerifier.prototype.assertNotDestroyed = function () {
_assert(!this.destroyed, this.auth, "internal-error" /* INTERNAL_ERROR */);
};
RecaptchaVerifier.prototype.makeRenderPromise = function () {
return __awaiter(this, void 0, void 0, function () {
var container, guaranteedEmpty;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.init()];
case 1:
_a.sent();
if (!this.widgetId) {
container = this.container;
if (!this.isInvisible) {
guaranteedEmpty = document.createElement('div');
container.appendChild(guaranteedEmpty);
container = guaranteedEmpty;
}
this.widgetId = this.getAssertedRecaptcha().render(container, this.parameters);
}
return [2 /*return*/, this.widgetId];
}
});
});
};
RecaptchaVerifier.prototype.init = function () {
return __awaiter(this, void 0, void 0, function () {
var _a, siteKey;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_assert(_isHttpOrHttps() && !_isWorker(), this.auth, "internal-error" /* INTERNAL_ERROR */);
return [4 /*yield*/, domReady()];
case 1:
_b.sent();
_a = this;
return [4 /*yield*/, this._recaptchaLoader.load(this.auth, this.auth.languageCode || undefined)];
case 2:
_a.recaptcha = _b.sent();
return [4 /*yield*/, getRecaptchaParams(this.auth)];
case 3:
siteKey = _b.sent();
_assert(siteKey, this.auth, "internal-error" /* INTERNAL_ERROR */);
this.parameters.sitekey = siteKey;
return [2 /*return*/];
}
});
});
};
RecaptchaVerifier.prototype.getAssertedRecaptcha = function () {
_assert(this.recaptcha, this.auth, "internal-error" /* INTERNAL_ERROR */);
return this.recaptcha;
};
return RecaptchaVerifier;
}());
function domReady() {
var resolver = null;
return new Promise(function (resolve) {
if (document.readyState === 'complete') {
resolve();
return;
}
// Document not ready, wait for load before resolving.
// Save resolver, so we can remove listener in case it was externally
// cancelled.
resolver = function () { return resolve(); };
window.addEventListener('load', resolver);
}).catch(function (e) {
if (resolver) {
window.removeEventListener('load', resolver);
}
throw e;
});
}
/**
* @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 ConfirmationResultImpl = /** @class */ (function () {
function ConfirmationResultImpl(verificationId, onConfirmation) {
this.verificationId = verificationId;
this.onConfirmation = onConfirmation;
}
ConfirmationResultImpl.prototype.confirm = function (verificationCode) {
var authCredential = PhoneAuthCredential._fromVerification(this.verificationId, verificationCode);
return this.onConfirmation(authCredential);
};
return ConfirmationResultImpl;
}());
/**
* Asynchronously signs in using a phone number.
*
* @remarks
* This method sends a code via SMS to the given
* phone number, and returns a {@link ConfirmationResult}. After the user
* provides the code sent to their phone, call {@link ConfirmationResult.confirm}
* with the code to sign the user in.
*
* For abuse prevention, this method also requires a {@link ApplicationVerifier}.
* This SDK includes a reCAPTCHA-based implementation, {@link RecaptchaVerifier}.
* This function can work on other platforms that do not support the
* {@link RecaptchaVerifier} (like React Native), but you need to use a
* third-party {@link ApplicationVerifier} implementation.
*
* @example
* ```javascript
* // 'recaptcha-container' is the ID of an element in the DOM.
* const applicationVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
* const confirmationResult = await signInWithPhoneNumber(auth, phoneNumber, applicationVerifier);
* // Obtain a verificationCode from the user.
* const credential = await confirmationResult.confirm(verificationCode);
* ```
*
* @param auth - The {@link Auth} instance.
* @param phoneNumber - The user's phone number in E.164 format (e.g. +16505550101).
* @param appVerifier - The {@link ApplicationVerifier}.
*
* @public
*/
function signInWithPhoneNumber(auth, phoneNumber, appVerifier) {
return __awaiter(this, void 0, void 0, function () {
var authInternal, verificationId;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
authInternal = _castAuth(auth);
return [4 /*yield*/, _verifyPhoneNumber(authInternal, phoneNumber, getModularInstance(appVerifier))];
case 1:
verificationId = _a.sent();
return [2 /*return*/, new ConfirmationResultImpl(verificationId, function (cred) {
return signInWithCredential(authInternal, cred);
})];
}
});
});
}
/**
* Links the user account with the given phone number.
*
* @param user - The user.
* @param phoneNumber - The user's phone number in E.164 format (e.g. +16505550101).
* @param appVerifier - The {@link ApplicationVerifier}.
*
* @public
*/
function linkWithPhoneNumber(user, phoneNumber, appVerifier) {
return __awaiter(this, void 0, void 0, function () {
var userInternal, verificationId;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
userInternal = getModularInstance(user);
return [4 /*yield*/, _assertLinkedStatus(false, userInternal, "phone" /* PHONE */)];
case 1:
_a.sent();
return [4 /*yield*/, _verifyPhoneNumber(userInternal.auth, phoneNumber, getModularInstance(appVerifier))];
case 2:
verificationId = _a.sent();
return [2 /*return*/, new ConfirmationResultImpl(verificationId, function (cred) {
return linkWithCredential(userInternal, cred);
})];
}
});
});
}
/**
* Re-authenticates a user using a fresh phone credential.
*
* @remarks Use before operations such as {@link updatePassword} that require tokens from recent sign-in attempts.
*
* @param user - The user.
* @param phoneNumber - The user's phone number in E.164 format (e.g. +16505550101).
* @param appVerifier - The {@link ApplicationVerifier}.
*
* @public
*/
function reauthenticateWithPhoneNumber(user, phoneNumber, appVerifier) {
return __awaiter(this, void 0, void 0, function () {
var userInternal, verificationId;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
userInternal = getModularInstance(user);
return [4 /*yield*/, _verifyPhoneNumber(userInternal.auth, phoneNumber, getModularInstance(appVerifier))];
case 1:
verificationId = _a.sent();
return [2 /*return*/, new ConfirmationResultImpl(verificationId, function (cred) {
return reauthenticateWithCredential(userInternal, cred);
})];
}
});
});
}
/**
* Returns a verification ID to be used in conjunction with the SMS code that is sent.
*
*/
function _verifyPhoneNumber(auth, options, verifier) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var recaptchaToken, phoneInfoOptions, session, response, mfaEnrollmentId, response, sessionInfo;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, verifier.verify()];
case 1:
recaptchaToken = _b.sent();
_b.label = 2;
case 2:
_b.trys.push([2, , 10, 11]);
_assert(typeof recaptchaToken === 'string', auth, "argument-error" /* ARGUMENT_ERROR */);
_assert(verifier.type === RECAPTCHA_VERIFIER_TYPE, auth, "argument-error" /* ARGUMENT_ERROR */);
phoneInfoOptions = void 0;
if (typeof options === 'string') {
phoneInfoOptions = {
phoneNumber: options
};
}
else {
phoneInfoOptions = options;
}
if (!('session' in phoneInfoOptions)) return [3 /*break*/, 7];
session = phoneInfoOptions.session;
if (!('phoneNumber' in phoneInfoOptions)) return [3 /*break*/, 4];
_assert(session.type === "enroll" /* ENROLL */, auth, "internal-error" /* INTERNAL_ERROR */);
return [4 /*yield*/, startEnrollPhoneMfa(auth, {
idToken: session.credential,
phoneEnrollmentInfo: {
phoneNumber: phoneInfoOptions.phoneNumber,
recaptchaToken: recaptchaToken
}
})];
case 3:
response = _b.sent();
return [2 /*return*/, response.phoneSessionInfo.sessionInfo];
case 4:
_assert(session.type === "signin" /* SIGN_IN */, auth, "internal-error" /* INTERNAL_ERROR */);
mfaEnrollmentId = ((_a = phoneInfoOptions.multiFactorHint) === null || _a === void 0 ? void 0 : _a.uid) ||
phoneInfoOptions.multiFactorUid;
_assert(mfaEnrollmentId, auth, "missing-multi-factor-info" /* MISSING_MFA_INFO */);
return [4 /*yield*/, startSignInPhoneMfa(auth, {
mfaPendingCredential: session.credential,
mfaEnrollmentId: mfaEnrollmentId,
phoneSignInInfo: {
recaptchaToken: recaptchaToken
}
})];
case 5:
response = _b.sent();
return [2 /*return*/, response.phoneResponseInfo.sessionInfo];
case 6: return [3 /*break*/, 9];
case 7: return [4 /*yield*/, sendPhoneVerificationCode(auth, {
phoneNumber: phoneInfoOptions.phoneNumber,
recaptchaToken: recaptchaToken
})];
case 8:
sessionInfo = (_b.sent()).sessionInfo;
return [2 /*return*/, sessionInfo];
case 9: return [3 /*break*/, 11];
case 10:
verifier._reset();
return [7 /*endfinally*/];
case 11: return [2 /*return*/];
}
});
});
}
/**
* Updates the user's phone number.
*
* @example
* ```
* // 'recaptcha-container' is the ID of an element in the DOM.
* const applicationVerifier = new RecaptchaVerifier('recaptcha-container');
* const provider = new PhoneAuthProvider(auth);
* const verificationId = await provider.verifyPhoneNumber('+16505550101', applicationVerifier);
* // Obtain the verificationCode from the user.
* const phoneCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
* await updatePhoneNumber(user, phoneCredential);
* ```
*
* @param user - The user.
* @param credential - A credential authenticating the new phone number.
*
* @public
*/
function updatePhoneNumber(user, credential) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, _link(getModularInstance(user), credential)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
}
/**
* @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.
*/
/**
* Provider for generating an {@link PhoneAuthCredential}.
*
* @example
* ```javascript
* // 'recaptcha-container' is the ID of an element in the DOM.
* const applicationVerifier = new RecaptchaVerifier('recaptcha-container');
* const provider = new PhoneAuthProvider(auth);
* const verificationId = await provider.verifyPhoneNumber('+16505550101', applicationVerifier);
* // Obtain the verificationCode from the user.
* const phoneCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
* const userCredential = await signInWithCredential(auth, phoneCredential);
* ```
*
* @public
*/
var PhoneAuthProvider = /** @class */ (function () {
/**
* @param auth - The Firebase {@link Auth} instance in which sign-ins should occur.
*
*/
function PhoneAuthProvider(auth) {
/** Always set to {@link ProviderId}.PHONE. */
this.providerId = PhoneAuthProvider.PROVIDER_ID;
this.auth = _castAuth(auth);
}
/**
*
* Starts a phone number authentication flow by sending a verification code to the given phone
* number.
*
* @example
* ```javascript
* const provider = new PhoneAuthProvider(auth);
* const verificationId = await provider.verifyPhoneNumber(phoneNumber, applicationVerifier);
* // Obtain verificationCode from the user.
* const authCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
* const userCredential = await signInWithCredential(auth, authCredential);
* ```
*
* @example
* An alternative flow is provided using the `signInWithPhoneNumber` method.
* ```javascript
* const confirmationResult = signInWithPhoneNumber(auth, phoneNumber, applicationVerifier);
* // Obtain verificationCode from the user.
* const userCredential = confirmationResult.confirm(verificationCode);
* ```
*
* @param phoneInfoOptions - The user's {@link PhoneInfoOptions}. The phone number should be in
* E.164 format (e.g. +16505550101).
* @param applicationVerifier - For abuse prevention, this method also requires a
* {@link ApplicationVerifier}. This SDK includes a reCAPTCHA-based implementation,
* {@link RecaptchaVerifier}.
*
* @returns A Promise for a verification ID that can be passed to
* {@link PhoneAuthProvider.credential} to identify this flow..
*/
PhoneAuthProvider.prototype.verifyPhoneNumber = function (phoneOptions, applicationVerifier) {
return _verifyPhoneNumber(this.auth, phoneOptions, getModularInstance(applicationVerifier));
};
/**
* Creates a phone auth credential, given the verification ID from
* {@link PhoneAuthProvider.verifyPhoneNumber} and the code that was sent to the user's
* mobile device.
*
* @example
* ```javascript
* const provider = new PhoneAuthProvider(auth);
* const verificationId = provider.verifyPhoneNumber(phoneNumber, applicationVerifier);
* // Obtain verificationCode from the user.
* const authCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
* const userCredential = signInWithCredential(auth, authCredential);
* ```
*
* @example
* An alternative flow is provided using the `signInWithPhoneNumber` method.
* ```javascript
* const confirmationResult = await signInWithPhoneNumber(auth, phoneNumber, applicationVerifier);
* // Obtain verificationCode from the user.
* const userCredential = await confirmationResult.confirm(verificationCode);
* ```
*
* @param verificationId - The verification ID returned from {@link PhoneAuthProvider.verifyPhoneNumber}.
* @param verificationCode - The verification code sent to the user's mobile device.
*
* @returns The auth provider credential.
*/
PhoneAuthProvider.credential = function (verificationId, verificationCode) {
return PhoneAuthCredential._fromVerification(verificationId, verificationCode);
};
/**
* Generates an {@link AuthCredential} from a {@link UserCredential}.
* @param userCredential - The user credential.
*/
PhoneAuthProvider.credentialFromResult = function (userCredential) {
var credential = userCredential;
return PhoneAuthProvider.credentialFromTaggedObject(credential);
};
/**
* Returns an {@link AuthCredential} when passed an error.
*
* @remarks
*
* This method works for errors like
* `auth/account-exists-with-different-credentials`. This is useful for
* recovering when attempting to set a user's phone number but the number
* in question is already tied to another account. For example, the following
* code tries to update the current user's phone number, and if that
* fails, links the user with the account associated with that number:
*
* ```js
* const provider = new PhoneAuthProvider(auth);
* const verificationId = await provider.verifyPhoneNumber(number, verifier);
* try {
* const code = ''; // Prompt the user for the verification code
* await updatePhoneNumber(
* auth.currentUser,
* PhoneAuthProvider.credential(verificationId, code));
* } catch (e) {
* if (e.code === 'auth/account-exists-with-different-credential') {
* const cred = PhoneAuthProvider.credentialFromError(e);
* await linkWithCredential(auth.currentUser, cred);
* }
* }
*
* // At this point, auth.currentUser.phoneNumber === number.
* ```
*
* @param error - The error to generate a credential from.
*/
PhoneAuthProvider.credentialFromError = function (error) {
return PhoneAuthProvider.credentialFromTaggedObject((error.customData || {}));
};
PhoneAuthProvider.credentialFromTaggedObject = function (_a) {
var tokenResponse = _a._tokenResponse;
if (!tokenResponse) {
return null;
}
var _b = tokenResponse, phoneNumber = _b.phoneNumber, temporaryProof = _b.temporaryProof;
if (phoneNumber && temporaryProof) {
return PhoneAuthCredential._fromTokenResponse(phoneNumber, temporaryProof);
}
return null;
};
/** Always set to {@link ProviderId}.PHONE. */
PhoneAuthProvider.PROVIDER_ID = "phone" /* PHONE */;
/** Always set to {@link SignInMethod}.PHONE. */
PhoneAuthProvider.PHONE_SIGN_IN_METHOD = "phone" /* PHONE */;
return PhoneAuthProvider;
}());
/**
* @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 _POLL_WINDOW_CLOSE_TIMEOUT = new Delay(2000, 10000);
/**
* Authenticates a Firebase client using a popup-based OAuth authentication flow.
*
* @remarks
* If succeeds, returns the signed in user along with the provider's credential. If sign in was
* unsuccessful, returns an error object containing additional information about the error.
*
* @example
* ```javascript
* // Sign in using a popup.
* const provider = new FacebookAuthProvider();
* const result = await signInWithPopup(auth, provider);
*
* // The signed-in user info.
* const user = result.user;
* // This gives you a Facebook Access Token.
* const credential = provider.credentialFromResult(auth, result);
* const token = credential.accessToken;
* ```
*
* @param auth - The {@link Auth} instance.
* @param provider - The provider to authenticate. The provider has to be an {@link OAuthProvider}.
* Non-OAuth providers like {@link EmailAuthProvider} will throw an error.
* @param resolver - An instance of {@link PopupRedirectResolver}, optional
* if already supplied to {@link initializeAuth} or provided by {@link getAuth}.
*
*
* @public
*/
function signInWithPopup(auth, provider, resolver) {
return __awaiter(this, void 0, void 0, function () {
var authInternal, resolverInternal, action;
return __generator(this, function (_a) {
authInternal = _castAuth(auth);
_assertInstanceOf(auth, provider, FederatedAuthProvider);
resolverInternal = _withDefaultResolver(authInternal, resolver);
action = new PopupOperation(authInternal, "signInViaPopup" /* SIGN_IN_VIA_POPUP */, provider, resolverInternal);
return [2 /*return*/, action.executeNotNull()];
});
});
}
/**
* Reauthenticates the current user with the specified {@link OAuthProvider} using a pop-up based
* OAuth flow.
*
* @remarks
* If the reauthentication is successful, the returned result will contain the user and the
* provider's credential.
*
* @example
* ```javascript
* // Sign in using a popup.
* const provider = new FacebookAuthProvider();
* const result = await signInWithPopup(auth, provider);
* // Reauthenticate using a popup.
* await reauthenticateWithPopup(result.user, provider);
* ```
*
* @param user - The user.
* @param provider - The provider to authenticate. The provider has to be an {@link OAuthProvider}.
* Non-OAuth providers like {@link EmailAuthProvider} will throw an error.
* @param resolver - An instance of {@link PopupRedirectResolver}, optional
* if already supplied to {@link initializeAuth} or provided by {@link getAuth}.
*
* @public
*/
function reauthenticateWithPopup(user, provider, resolver) {
return __awaiter(this, void 0, void 0, function () {
var userInternal, resolverInternal, action;
return __generator(this, function (_a) {
userInternal = getModularInstance(user);
_assertInstanceOf(userInternal.auth, provider, FederatedAuthProvider);
resolverInternal = _withDefaultResolver(userInternal.auth, resolver);
action = new PopupOperation(userInternal.auth, "reauthViaPopup" /* REAUTH_VIA_POPUP */, provider, resolverInternal, userInternal);
return [2 /*return*/, action.executeNotNull()];
});
});
}
/**
* Links the authenticated provider to the user account using a pop-up based OAuth flow.
*
* @remarks
* If the linking is successful, the returned result will contain the user and the provider's credential.
*
*
* @example
* ```javascript
* // Sign in using some other provider.
* const result = await signInWithEmailAndPassword(auth, email, password);
* // Link using a popup.
* const provider = new Faceboo