Estructura inicial del proyecto
This commit is contained in:
349
backend/node_modules/@azure/msal-browser/dist/utils/BrowserUtils.mjs
generated
vendored
Normal file
349
backend/node_modules/@azure/msal-browser/dist/utils/BrowserUtils.mjs
generated
vendored
Normal file
@ -0,0 +1,349 @@
|
||||
/*! @azure/msal-browser v5.11.0 2026-05-19 */
|
||||
'use strict';
|
||||
import { RequestParameterBuilder, ProtocolUtils, UrlString, UrlUtils } from '@azure/msal-common/browser';
|
||||
export { invoke, invokeAsync } from '@azure/msal-common/browser';
|
||||
import { WaitForBridgeLateResponse } from '../telemetry/BrowserPerformanceEvents.mjs';
|
||||
import { createBrowserAuthError } from '../error/BrowserAuthError.mjs';
|
||||
import { InteractionType, BrowserCacheLocation } from './BrowserConstants.mjs';
|
||||
import { createNewGuid } from '../crypto/BrowserCrypto.mjs';
|
||||
import { createBrowserConfigurationAuthError } from '../error/BrowserConfigurationAuthError.mjs';
|
||||
import { timedOut, emptyResponse, noStateInHash, unableToParseState, interactionInProgressCancelled, redirectBridgeEmptyResponse, blockIframeReload, redirectInIframe, blockNestedPopups, nonBrowserEnvironment, uninitializedPublicClientApplication } from '../error/BrowserAuthErrorCodes.mjs';
|
||||
import { base64Decode } from '../encode/Base64Decode.mjs';
|
||||
import { inMemRedirectUnavailable } from '../error/BrowserConfigurationAuthErrorCodes.mjs';
|
||||
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
/**
|
||||
* Extracts and parses the authentication response from URL (hash and/or query string).
|
||||
* This is a shared utility used across multiple components in msal-browser.
|
||||
*
|
||||
* @returns {Object} An object containing the parsed state information and URL parameters.
|
||||
* @returns {URLSearchParams} params - The parsed URL parameters from the payload.
|
||||
* @returns {string} payload - The combined query string and hash content.
|
||||
* @returns {string} urlHash - The original URL hash.
|
||||
* @returns {string} urlQuery - The original URL query string.
|
||||
* @returns {LibraryStateObject} libraryState - The decoded library state from the state parameter.
|
||||
*
|
||||
* @throws {AuthError} If no authentication payload is found in the URL.
|
||||
* @throws {AuthError} If the state parameter is missing.
|
||||
* @throws {AuthError} If the state is missing required 'id' or 'meta' attributes.
|
||||
*/
|
||||
function parseAuthResponseFromUrl() {
|
||||
// Extract both hash and query string to support hybrid response format
|
||||
const urlHash = window.location.hash;
|
||||
const urlQuery = window.location.search;
|
||||
// Determine which part contains the auth response by checking for 'state' parameter
|
||||
let hasResponseInHash = false;
|
||||
let hasResponseInQuery = false;
|
||||
let payload = "";
|
||||
let params = undefined;
|
||||
if (urlHash && urlHash.length > 1) {
|
||||
const hashContent = urlHash.charAt(0) === "#" ? urlHash.substring(1) : urlHash;
|
||||
const hashParams = new URLSearchParams(hashContent);
|
||||
if (hashParams.has("state")) {
|
||||
hasResponseInHash = true;
|
||||
payload = hashContent;
|
||||
params = hashParams;
|
||||
}
|
||||
}
|
||||
if (urlQuery && urlQuery.length > 1) {
|
||||
const queryContent = urlQuery.charAt(0) === "?" ? urlQuery.substring(1) : urlQuery;
|
||||
const queryParams = new URLSearchParams(queryContent);
|
||||
if (queryParams.has("state")) {
|
||||
hasResponseInQuery = true;
|
||||
payload = queryContent;
|
||||
params = queryParams;
|
||||
}
|
||||
}
|
||||
// If response is in both, combine them (hybrid format)
|
||||
if (hasResponseInHash && hasResponseInQuery) {
|
||||
const queryContent = urlQuery.charAt(0) === "?" ? urlQuery.substring(1) : urlQuery;
|
||||
const hashContent = urlHash.charAt(0) === "#" ? urlHash.substring(1) : urlHash;
|
||||
payload = `${queryContent}${hashContent}`;
|
||||
params = new URLSearchParams(payload);
|
||||
}
|
||||
if (!payload || !params) {
|
||||
throw createBrowserAuthError(emptyResponse);
|
||||
}
|
||||
const state = params.get("state");
|
||||
if (!state) {
|
||||
throw createBrowserAuthError(noStateInHash);
|
||||
}
|
||||
const { libraryState } = ProtocolUtils.parseRequestState(base64Decode, state);
|
||||
const { id, meta } = libraryState;
|
||||
if (!id || !meta) {
|
||||
throw createBrowserAuthError(unableToParseState, "missing_library_state");
|
||||
}
|
||||
return {
|
||||
params,
|
||||
payload,
|
||||
urlHash,
|
||||
urlQuery,
|
||||
hasResponseInHash,
|
||||
hasResponseInQuery,
|
||||
libraryState: {
|
||||
id,
|
||||
meta,
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Clears hash from window url.
|
||||
*/
|
||||
function clearHash(contentWindow) {
|
||||
// Office.js sets history.replaceState to null
|
||||
contentWindow.location.hash = "";
|
||||
if (typeof contentWindow.history.replaceState === "function") {
|
||||
// Full removes "#" from url
|
||||
contentWindow.history.replaceState(null, "", `${contentWindow.location.origin}${contentWindow.location.pathname}${contentWindow.location.search}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replaces current hash with hash from provided url
|
||||
*/
|
||||
function replaceHash(url) {
|
||||
const urlParts = url.split("#");
|
||||
urlParts.shift(); // Remove part before the hash
|
||||
window.location.hash = urlParts.length > 0 ? urlParts.join("#") : "";
|
||||
}
|
||||
/**
|
||||
* Returns boolean of whether the current window is in an iframe or not.
|
||||
*/
|
||||
function isInIframe() {
|
||||
return window.parent !== window;
|
||||
}
|
||||
/**
|
||||
* Returns boolean of whether or not the current window is a popup opened by msal
|
||||
*/
|
||||
function isInPopup() {
|
||||
if (isInIframe()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const { libraryState } = parseAuthResponseFromUrl();
|
||||
const { meta } = libraryState;
|
||||
return meta["interactionType"] === InteractionType.Popup;
|
||||
}
|
||||
catch (e) {
|
||||
// If parsing fails (no state, invalid URL, etc.), we're not in a popup
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Await a response from a redirect bridge using BroadcastChannel.
|
||||
* This unified function works for both popup and iframe scenarios by listening on a
|
||||
* BroadcastChannel for the server payload.
|
||||
*
|
||||
* @param timeoutMs - Timeout in milliseconds.
|
||||
* @param logger - Logger instance for logging monitoring events.
|
||||
* @param browserCrypto - Browser crypto instance for decoding state.
|
||||
* @param request - The authorization or end session request.
|
||||
* @returns Promise<string> - Resolves with the response string (query or hash) from the window.
|
||||
*/
|
||||
// Track the active bridge monitor to allow cancellation when overriding interactions
|
||||
let activeBridgeMonitor = null;
|
||||
/**
|
||||
* Cancels the pending bridge response monitor if one exists.
|
||||
* This is called when overrideInteractionInProgress is used to cancel
|
||||
* any pending popup interaction before starting a new one.
|
||||
*/
|
||||
function cancelPendingBridgeResponse(logger, correlationId) {
|
||||
if (activeBridgeMonitor) {
|
||||
logger.verbose("18y01k", correlationId);
|
||||
clearTimeout(activeBridgeMonitor.timeoutId);
|
||||
activeBridgeMonitor.channel.close();
|
||||
activeBridgeMonitor.reject(createBrowserAuthError(interactionInProgressCancelled));
|
||||
activeBridgeMonitor = null;
|
||||
}
|
||||
}
|
||||
async function waitForBridgeResponse(timeoutMs, logger, browserCrypto, request, performanceClient, experimentalConfig) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logger.verbose("1rf6em", request.correlationId);
|
||||
const correlationId = request.correlationId;
|
||||
performanceClient.addFields({
|
||||
redirectBridgeTimeoutMs: timeoutMs,
|
||||
lateResponseExperimentEnabled: experimentalConfig?.iframeTimeoutTelemetry || false,
|
||||
}, correlationId);
|
||||
const { libraryState } = ProtocolUtils.parseRequestState(browserCrypto.base64Decode, request.state || "");
|
||||
const channel = new BroadcastChannel(libraryState.id);
|
||||
let responseString = undefined;
|
||||
let timedOut$1 = false;
|
||||
let lateTimeoutId;
|
||||
let lateMeasurement;
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
// Clear the active monitor
|
||||
activeBridgeMonitor = null;
|
||||
if (experimentalConfig?.iframeTimeoutTelemetry) {
|
||||
lateMeasurement = performanceClient.startMeasurement(WaitForBridgeLateResponse, correlationId);
|
||||
timedOut$1 = true;
|
||||
lateTimeoutId = window.setTimeout(() => {
|
||||
lateMeasurement?.end({ success: false });
|
||||
clearTimeout(lateTimeoutId);
|
||||
channel.close();
|
||||
}, 60000); // 60s late response timeout to allow for telemetry of late responses
|
||||
}
|
||||
else {
|
||||
channel.close();
|
||||
}
|
||||
reject(createBrowserAuthError(timedOut, "redirect_bridge_timeout"));
|
||||
}, timeoutMs);
|
||||
// Track this monitor so it can be cancelled if needed
|
||||
activeBridgeMonitor = {
|
||||
timeoutId,
|
||||
channel,
|
||||
reject,
|
||||
};
|
||||
channel.onmessage = (event) => {
|
||||
responseString = event.data.payload;
|
||||
const messageVersion = event?.data && typeof event.data.v === "number"
|
||||
? event.data.v
|
||||
: undefined;
|
||||
if (timedOut$1) {
|
||||
lateMeasurement?.end({
|
||||
success: responseString ? true : false,
|
||||
});
|
||||
clearTimeout(lateTimeoutId);
|
||||
channel.close();
|
||||
return;
|
||||
}
|
||||
performanceClient.addFields({
|
||||
redirectBridgeMessageVersion: messageVersion,
|
||||
}, correlationId);
|
||||
// Clear the active monitor
|
||||
activeBridgeMonitor = null;
|
||||
clearTimeout(timeoutId);
|
||||
channel.close();
|
||||
if (responseString) {
|
||||
resolve(responseString);
|
||||
}
|
||||
else {
|
||||
reject(createBrowserAuthError(redirectBridgeEmptyResponse));
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
// #endregion
|
||||
/**
|
||||
* Returns current window URL as redirect uri
|
||||
*/
|
||||
function getCurrentUri() {
|
||||
return typeof window !== "undefined" && window.location
|
||||
? window.location.href.split("?")[0].split("#")[0]
|
||||
: "";
|
||||
}
|
||||
/**
|
||||
* Gets the homepage url for the current window location.
|
||||
*/
|
||||
function getHomepage() {
|
||||
const currentUrl = new UrlString(window.location.href);
|
||||
const urlComponents = currentUrl.getUrlComponents();
|
||||
return `${urlComponents.Protocol}//${urlComponents.HostNameAndPort}/`;
|
||||
}
|
||||
/**
|
||||
* Throws error if we have completed an auth and are
|
||||
* attempting another auth request inside an iframe.
|
||||
*/
|
||||
function blockReloadInHiddenIframes() {
|
||||
const isResponseHash = UrlUtils.getDeserializedResponse(window.location.hash);
|
||||
// return an error if called from the hidden iframe created by the msal js silent calls
|
||||
if (isResponseHash && isInIframe()) {
|
||||
throw createBrowserAuthError(blockIframeReload);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Block redirect operations in iframes unless explicitly allowed
|
||||
* @param interactionType Interaction type for the request
|
||||
* @param allowRedirectInIframe Config value to allow redirects when app is inside an iframe
|
||||
*/
|
||||
function blockRedirectInIframe(allowRedirectInIframe) {
|
||||
if (isInIframe() && !allowRedirectInIframe) {
|
||||
// If we are not in top frame, we shouldn't redirect. This is also handled by the service.
|
||||
throw createBrowserAuthError(redirectInIframe);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Block redirectUri loaded in popup from calling AcquireToken APIs
|
||||
*/
|
||||
function blockAcquireTokenInPopups() {
|
||||
// Popups opened by msal popup APIs are given a name that starts with "msal."
|
||||
if (isInPopup()) {
|
||||
throw createBrowserAuthError(blockNestedPopups);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Throws error if token requests are made in non-browser environment
|
||||
* @param isBrowserEnvironment Flag indicating if environment is a browser.
|
||||
*/
|
||||
function blockNonBrowserEnvironment() {
|
||||
if (typeof window === "undefined") {
|
||||
throw createBrowserAuthError(nonBrowserEnvironment);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Throws error if initialize hasn't been called
|
||||
* @param initialized
|
||||
*/
|
||||
function blockAPICallsBeforeInitialize(initialized) {
|
||||
if (!initialized) {
|
||||
throw createBrowserAuthError(uninitializedPublicClientApplication);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Helper to validate app environment before making an auth request
|
||||
* @param initialized
|
||||
*/
|
||||
function preflightCheck(initialized) {
|
||||
// Block request if not in browser environment
|
||||
blockNonBrowserEnvironment();
|
||||
// Block auth requests inside a hidden iframe
|
||||
blockReloadInHiddenIframes();
|
||||
// Block redirectUri opened in a popup from calling MSAL APIs
|
||||
blockAcquireTokenInPopups();
|
||||
// Block token acquisition before initialize has been called
|
||||
blockAPICallsBeforeInitialize(initialized);
|
||||
}
|
||||
/**
|
||||
* Helper to validate app enviornment before making redirect request
|
||||
* @param initialized
|
||||
* @param config
|
||||
*/
|
||||
function redirectPreflightCheck(initialized, config) {
|
||||
preflightCheck(initialized);
|
||||
blockRedirectInIframe(config.system.allowRedirectInIframe);
|
||||
// Block redirects if memory storage is enabled
|
||||
if (config.cache.cacheLocation === BrowserCacheLocation.MemoryStorage) {
|
||||
throw createBrowserConfigurationAuthError(inMemRedirectUnavailable);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Adds a preconnect link element to the header which begins DNS resolution and SSL connection in anticipation of the /token request
|
||||
* @param loginDomain Authority domain, including https protocol e.g. https://login.microsoftonline.com
|
||||
* @returns
|
||||
*/
|
||||
function preconnect(authority) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "preconnect";
|
||||
link.href = new URL(authority).origin;
|
||||
link.crossOrigin = "anonymous";
|
||||
document.head.appendChild(link);
|
||||
// The browser will close connection if not used within a few seconds, remove element from the header after 10s
|
||||
window.setTimeout(() => {
|
||||
try {
|
||||
document.head.removeChild(link);
|
||||
}
|
||||
catch { }
|
||||
}, 10000); // 10s Timeout
|
||||
}
|
||||
/**
|
||||
* Wrapper function that creates a UUID v7 from the current timestamp.
|
||||
* @returns {string}
|
||||
*/
|
||||
function createGuid() {
|
||||
return createNewGuid();
|
||||
}
|
||||
const addClientCapabilitiesToClaims = RequestParameterBuilder.addClientCapabilitiesToClaims;
|
||||
|
||||
export { addClientCapabilitiesToClaims, blockAPICallsBeforeInitialize, blockAcquireTokenInPopups, blockNonBrowserEnvironment, blockRedirectInIframe, blockReloadInHiddenIframes, cancelPendingBridgeResponse, clearHash, createGuid, getCurrentUri, getHomepage, isInIframe, isInPopup, parseAuthResponseFromUrl, preconnect, preflightCheck, redirectPreflightCheck, replaceHash, waitForBridgeResponse };
|
||||
//# sourceMappingURL=BrowserUtils.mjs.map
|
||||
Reference in New Issue
Block a user