UNPKG

@firebase/auth

Version:

The Firebase Authenticaton component of the Firebase JS SDK.

1,112 lines (1,103 loc) 85.5 kB
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