UNPKG

voluptasmollitia

Version:
117 lines (107 loc) 3.92 kB
/** * @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. */ import { SDK_VERSION } from '@firebase/app-exp'; import { querystring } from '@firebase/util'; import { DefaultConfig } from '../../../internal'; import { AuthErrorCode } from '../../core/errors'; import { _assert, _createError } from '../../core/util/assert'; import { Delay } from '../../core/util/delay'; import { _emulatorUrl } from '../../core/util/emulator'; import { AuthInternal } from '../../model/auth'; import { _window } from '../auth_window'; import * as gapiLoader from './gapi'; const PING_TIMEOUT = new Delay(5000, 15000); const IFRAME_PATH = '__/auth/iframe'; const EMULATED_IFRAME_PATH = 'emulator/auth/iframe'; const IFRAME_ATTRIBUTES = { style: { position: 'absolute', top: '-100px', width: '1px', height: '1px' } }; // Map from apiHost to endpoint ID for passing into iframe. In current SDK, apiHost can be set to // anything (not from a list of endpoints with IDs as in legacy), so this is the closest we can get. const EID_FROM_APIHOST = new Map([ [DefaultConfig.API_HOST, 'p'], // production ['staging-identitytoolkit.sandbox.googleapis.com', 's'], // staging ['test-identitytoolkit.sandbox.googleapis.com', 't'] // test ]); function getIframeUrl(auth: AuthInternal): string { const config = auth.config; _assert(config.authDomain, auth, AuthErrorCode.MISSING_AUTH_DOMAIN); const url = config.emulator ? _emulatorUrl(config, EMULATED_IFRAME_PATH) : `https://${auth.config.authDomain}/${IFRAME_PATH}`; const params: Record<string, string> = { apiKey: config.apiKey, appName: auth.name, v: SDK_VERSION }; const eid = EID_FROM_APIHOST.get(auth.config.apiHost); if (eid) { params.eid = eid; } const frameworks = auth._getFrameworks(); if (frameworks.length) { params.fw = frameworks.join(','); } return `${url}?${querystring(params).slice(1)}`; } export async function _openIframe( auth: AuthInternal ): Promise<gapi.iframes.Iframe> { const context = await gapiLoader._loadGapi(auth); const gapi = _window().gapi; _assert(gapi, auth, AuthErrorCode.INTERNAL_ERROR); return context.open( { where: document.body, url: getIframeUrl(auth), messageHandlersFilter: gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER, attributes: IFRAME_ATTRIBUTES, dontclear: true }, (iframe: gapi.iframes.Iframe) => new Promise(async (resolve, reject) => { await iframe.restyle({ // Prevent iframe from closing on mouse out. setHideOnLeave: false }); const networkError = _createError( auth, AuthErrorCode.NETWORK_REQUEST_FAILED ); // Confirm iframe is correctly loaded. // To fallback on failure, set a timeout. const networkErrorTimer = _window().setTimeout(() => { reject(networkError); }, PING_TIMEOUT.get()); // Clear timer and resolve pending iframe ready promise. function clearTimerAndResolve(): void { _window().clearTimeout(networkErrorTimer); resolve(iframe); } // This returns an IThenable. However the reject part does not call // when the iframe is not loaded. iframe.ping(clearTimerAndResolve).then(clearTimerAndResolve, () => { reject(networkError); }); }) ); }