/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { Logger, IPerformanceClient, PerformanceEvents, invokeAsync, invoke, ServerResponseType, } from "@azure/msal-common"; import { createBrowserAuthError, BrowserAuthErrorCodes, } from "../error/BrowserAuthError"; import { DEFAULT_IFRAME_TIMEOUT_MS } from "../config/Configuration"; /** * Creates a hidden iframe to given URL using user-requested scopes as an id. * @param urlNavigate * @param userRequestScopes */ export async function initiateAuthRequest( requestUrl: string, performanceClient: IPerformanceClient, logger: Logger, correlationId: string, navigateFrameWait?: number ): Promise { performanceClient.addQueueMeasurement( PerformanceEvents.SilentHandlerInitiateAuthRequest, correlationId ); if (!requestUrl) { // Throw error if request URL is empty. logger.info("Navigate url is empty"); throw createBrowserAuthError(BrowserAuthErrorCodes.emptyNavigateUri); } if (navigateFrameWait) { return invokeAsync( loadFrame, PerformanceEvents.SilentHandlerLoadFrame, logger, performanceClient, correlationId )(requestUrl, navigateFrameWait, performanceClient, correlationId); } return invoke( loadFrameSync, PerformanceEvents.SilentHandlerLoadFrameSync, logger, performanceClient, correlationId )(requestUrl); } /** * Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout. * @param iframe * @param timeout */ export async function monitorIframeForHash( iframe: HTMLIFrameElement, timeout: number, pollIntervalMilliseconds: number, performanceClient: IPerformanceClient, logger: Logger, correlationId: string, responseType: ServerResponseType ): Promise { performanceClient.addQueueMeasurement( PerformanceEvents.SilentHandlerMonitorIframeForHash, correlationId ); return new Promise((resolve, reject) => { if (timeout < DEFAULT_IFRAME_TIMEOUT_MS) { logger.warning( `system.loadFrameTimeout or system.iframeHashTimeout set to lower (${timeout}ms) than the default (${DEFAULT_IFRAME_TIMEOUT_MS}ms). This may result in timeouts.` ); } /* * Polling for iframes can be purely timing based, * since we don't need to account for interaction. */ const timeoutId = window.setTimeout(() => { window.clearInterval(intervalId); reject( createBrowserAuthError( BrowserAuthErrorCodes.monitorWindowTimeout ) ); }, timeout); const intervalId = window.setInterval(() => { let href: string = ""; const contentWindow = iframe.contentWindow; try { /* * Will throw if cross origin, * which should be caught and ignored * since we need the interval to keep running while on STS UI. */ href = contentWindow ? contentWindow.location.href : ""; } catch (e) {} if (!href || href === "about:blank") { return; } let responseString = ""; if (contentWindow) { if (responseType === ServerResponseType.QUERY) { responseString = contentWindow.location.search; } else { responseString = contentWindow.location.hash; } } window.clearTimeout(timeoutId); window.clearInterval(intervalId); resolve(responseString); }, pollIntervalMilliseconds); }).finally(() => { invoke( removeHiddenIframe, PerformanceEvents.RemoveHiddenIframe,