@azure/msal-browser
Advanced tools
Comparing version 3.2.0 to 3.3.0
@@ -1,2 +0,2 @@ | ||
import { CommonAuthorizationCodeRequest, ICrypto, AccountEntity, IdTokenEntity, AccessTokenEntity, RefreshTokenEntity, AppMetadataEntity, CacheManager, ServerTelemetryEntity, ThrottlingEntity, Logger, AuthorityMetadataEntity, AccountInfo, ValidCredentialType, TokenKeys, CredentialType, IPerformanceClient } from "@azure/msal-common"; | ||
import { CommonAuthorizationCodeRequest, ICrypto, AccountEntity, IdTokenEntity, AccessTokenEntity, RefreshTokenEntity, AppMetadataEntity, CacheManager, ServerTelemetryEntity, ThrottlingEntity, Logger, AuthorityMetadataEntity, AccountInfo, ValidCredentialType, TokenKeys, CredentialType, IPerformanceClient, StaticAuthorityOptions } from "@azure/msal-common"; | ||
import { CacheOptions } from "../config/Configuration"; | ||
@@ -24,3 +24,3 @@ import { BrowserCacheLocation, InteractionType } from "../utils/BrowserConstants"; | ||
protected readonly COOKIE_LIFE_MULTIPLIER: number; | ||
constructor(clientId: string, cacheConfig: Required<CacheOptions>, cryptoImpl: ICrypto, logger: Logger); | ||
constructor(clientId: string, cacheConfig: Required<CacheOptions>, cryptoImpl: ICrypto, logger: Logger, staticAuthorityOptions?: StaticAuthorityOptions); | ||
/** | ||
@@ -217,13 +217,2 @@ * Returns a window storage class implementing the IWindowStorage interface that corresponds to the configured cacheLocation. | ||
/** | ||
* Gets a list of accounts that match all of the filters provided | ||
* @param account | ||
*/ | ||
getAccountInfoByFilter(accountFilter: Partial<Omit<AccountInfo, "idTokenClaims" | "name">>): AccountInfo[]; | ||
/** | ||
* Checks the cache for accounts matching loginHint or SID | ||
* @param loginHint | ||
* @param sid | ||
*/ | ||
getAccountInfoByHints(loginHint?: string, sid?: string): AccountInfo | null; | ||
/** | ||
* fetch throttling entity from the platform cache | ||
@@ -230,0 +219,0 @@ * @param throttlingCacheKey |
@@ -64,2 +64,6 @@ import { SystemOptions, LoggerOptions, INetworkModule, ProtocolMode, OIDCOptions, AzureCloudOptions, ApplicationTelemetry, IPerformanceClient } from "@azure/msal-common"; | ||
skipAuthorityMetadataCache?: boolean; | ||
/** | ||
* App supports nested app auth or not; defaults to false | ||
*/ | ||
supportsNestedAppAuth?: boolean; | ||
}; | ||
@@ -66,0 +70,0 @@ /** @internal */ |
@@ -8,4 +8,5 @@ import { IController } from "./IController"; | ||
constructor(config: Configuration); | ||
createController(): Promise<IController>; | ||
createV3Controller(): Promise<IController>; | ||
createController(): Promise<IController | null>; | ||
} | ||
//# sourceMappingURL=ControllerFactory.d.ts.map |
@@ -5,11 +5,9 @@ /** | ||
*/ | ||
/** | ||
* Warning: This set of exports is purely intended to be used by other MSAL libraries, and should be considered potentially unstable. We strongly discourage using them directly, you do so at your own risk. | ||
* Breaking changes to these APIs will be shipped under a minor version, instead of a major version. | ||
*/ | ||
import * as BrowserUtils from "./utils/BrowserUtils"; | ||
export { BrowserUtils }; | ||
export { PublicClientApplication } from "./app/PublicClientApplication"; | ||
export { PublicClientNext } from "./app/PublicClientNext"; | ||
export { IController } from "./controllers/IController"; | ||
export { Configuration, BrowserAuthOptions, CacheOptions, BrowserSystemOptions, BrowserTelemetryOptions, BrowserConfiguration, DEFAULT_IFRAME_TIMEOUT_MS, } from "./config/Configuration"; | ||
export { InteractionType, InteractionStatus, BrowserCacheLocation, WrapperSKU, ApiId, CacheLookupPolicy, } from "./utils/BrowserConstants"; | ||
export { BrowserUtils } from "./utils/BrowserUtils"; | ||
export { BrowserAuthError, BrowserAuthErrorMessage, BrowserAuthErrorCodes, } from "./error/BrowserAuthError"; | ||
@@ -16,0 +14,0 @@ export { BrowserConfigurationAuthError, BrowserConfigurationAuthErrorCodes, BrowserConfigurationAuthErrorMessage, } from "./error/BrowserConfigurationAuthError"; |
@@ -1,48 +0,14 @@ | ||
import { CommonAuthorizationCodeRequest, AuthorizationCodeClient, Logger, IPerformanceClient } from "@azure/msal-common"; | ||
import { InteractionHandler } from "./InteractionHandler"; | ||
import { BrowserCacheManager } from "../cache/BrowserCacheManager"; | ||
import { BrowserSystemOptions } from "../config/Configuration"; | ||
export declare class SilentHandler extends InteractionHandler { | ||
private navigateFrameWait; | ||
private pollIntervalMilliseconds; | ||
constructor(authCodeModule: AuthorizationCodeClient, storageImpl: BrowserCacheManager, authCodeRequest: CommonAuthorizationCodeRequest, logger: Logger, systemOptions: Required<Pick<BrowserSystemOptions, "navigateFrameWait" | "pollIntervalMilliseconds">>, performanceClient: IPerformanceClient); | ||
/** | ||
* Creates a hidden iframe to given URL using user-requested scopes as an id. | ||
* @param urlNavigate | ||
* @param userRequestScopes | ||
*/ | ||
initiateAuthRequest(requestUrl: string): Promise<HTMLIFrameElement>; | ||
/** | ||
* Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout. | ||
* @param iframe | ||
* @param timeout | ||
*/ | ||
monitorIframeForHash(iframe: HTMLIFrameElement, timeout: number): Promise<string>; | ||
/** | ||
* @hidden | ||
* Loads iframe with authorization endpoint URL | ||
* @ignore | ||
*/ | ||
private loadFrame; | ||
/** | ||
* @hidden | ||
* Loads the iframe synchronously when the navigateTimeFrame is set to `0` | ||
* @param urlNavigate | ||
* @param frameName | ||
* @param logger | ||
*/ | ||
private loadFrameSync; | ||
/** | ||
* @hidden | ||
* Creates a new hidden iframe or gets an existing one for silent token renewal. | ||
* @ignore | ||
*/ | ||
private createHiddenIframe; | ||
/** | ||
* @hidden | ||
* Removes a hidden iframe from the page. | ||
* @ignore | ||
*/ | ||
private removeHiddenIframe; | ||
} | ||
import { Logger, IPerformanceClient } from "@azure/msal-common"; | ||
/** | ||
* Creates a hidden iframe to given URL using user-requested scopes as an id. | ||
* @param urlNavigate | ||
* @param userRequestScopes | ||
*/ | ||
export declare function initiateAuthRequest(requestUrl: string, performanceClient: IPerformanceClient, logger: Logger, correlationId: string, navigateFrameWait?: number): Promise<HTMLIFrameElement>; | ||
/** | ||
* Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout. | ||
* @param iframe | ||
* @param timeout | ||
*/ | ||
export declare function monitorIframeForHash(iframe: HTMLIFrameElement, timeout: number, pollIntervalMilliseconds: number, performanceClient: IPerformanceClient, logger: Logger, correlationId: string): Promise<string>; | ||
//# sourceMappingURL=SilentHandler.d.ts.map |
import { BaseOperatingContext } from "./BaseOperatingContext"; | ||
import { IBridgeProxy } from "../naa/IBridgeProxy"; | ||
import { AccountInfo } from "../naa/AccountInfo"; | ||
export declare class TeamsAppOperatingContext extends BaseOperatingContext { | ||
protected bridgeProxy: IBridgeProxy | undefined; | ||
protected activeAccount: AccountInfo | undefined; | ||
static readonly MODULE_NAME: string; | ||
@@ -19,2 +23,5 @@ /** | ||
getId(): string; | ||
getBridgeProxy(): IBridgeProxy | undefined; | ||
getActiveAccount(): AccountInfo | undefined; | ||
setActiveAccount(account: AccountInfo): void; | ||
/** | ||
@@ -21,0 +28,0 @@ * Checks whether the operating context is available. |
export declare const name = "@azure/msal-browser"; | ||
export declare const version = "3.2.0"; | ||
export declare const version = "3.3.0"; | ||
//# sourceMappingURL=packageMetadata.d.ts.map |
import { InteractionType } from "./BrowserConstants"; | ||
/** | ||
* Utility class for browser specific functions | ||
* Clears hash from window url. | ||
*/ | ||
export declare class BrowserUtils { | ||
/** | ||
* Clears hash from window url. | ||
*/ | ||
static clearHash(contentWindow: Window): void; | ||
/** | ||
* Replaces current hash with hash from provided url | ||
*/ | ||
static replaceHash(url: string): void; | ||
/** | ||
* Returns boolean of whether the current window is in an iframe or not. | ||
*/ | ||
static isInIframe(): boolean; | ||
/** | ||
* Returns boolean of whether or not the current window is a popup opened by msal | ||
*/ | ||
static isInPopup(): boolean; | ||
/** | ||
* Returns current window URL as redirect uri | ||
*/ | ||
static getCurrentUri(): string; | ||
/** | ||
* Gets the homepage url for the current window location. | ||
*/ | ||
static getHomepage(): string; | ||
/** | ||
* Throws error if we have completed an auth and are | ||
* attempting another auth request inside an iframe. | ||
*/ | ||
static blockReloadInHiddenIframes(): void; | ||
/** | ||
* 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 | ||
*/ | ||
static blockRedirectInIframe(interactionType: InteractionType, allowRedirectInIframe: boolean): void; | ||
/** | ||
* Block redirectUri loaded in popup from calling AcquireToken APIs | ||
*/ | ||
static blockAcquireTokenInPopups(): void; | ||
/** | ||
* Throws error if token requests are made in non-browser environment | ||
* @param isBrowserEnvironment Flag indicating if environment is a browser. | ||
*/ | ||
static blockNonBrowserEnvironment(isBrowserEnvironment: boolean): void; | ||
/** | ||
* Throws error if initialize hasn't been called | ||
* @param initialized | ||
*/ | ||
static blockAPICallsBeforeInitialize(initialized: boolean): void; | ||
} | ||
export declare function clearHash(contentWindow: Window): void; | ||
/** | ||
* Replaces current hash with hash from provided url | ||
*/ | ||
export declare function replaceHash(url: string): void; | ||
/** | ||
* Returns boolean of whether the current window is in an iframe or not. | ||
*/ | ||
export declare function isInIframe(): boolean; | ||
/** | ||
* Returns boolean of whether or not the current window is a popup opened by msal | ||
*/ | ||
export declare function isInPopup(): boolean; | ||
/** | ||
* Returns current window URL as redirect uri | ||
*/ | ||
export declare function getCurrentUri(): string; | ||
/** | ||
* Gets the homepage url for the current window location. | ||
*/ | ||
export declare function getHomepage(): string; | ||
/** | ||
* Throws error if we have completed an auth and are | ||
* attempting another auth request inside an iframe. | ||
*/ | ||
export declare function blockReloadInHiddenIframes(): void; | ||
/** | ||
* 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 | ||
*/ | ||
export declare function blockRedirectInIframe(interactionType: InteractionType, allowRedirectInIframe: boolean): void; | ||
/** | ||
* Block redirectUri loaded in popup from calling AcquireToken APIs | ||
*/ | ||
export declare function blockAcquireTokenInPopups(): void; | ||
/** | ||
* Throws error if token requests are made in non-browser environment | ||
* @param isBrowserEnvironment Flag indicating if environment is a browser. | ||
*/ | ||
export declare function blockNonBrowserEnvironment(isBrowserEnvironment: boolean): void; | ||
/** | ||
* Throws error if initialize hasn't been called | ||
* @param initialized | ||
*/ | ||
export declare function blockAPICallsBeforeInitialize(initialized: boolean): void; | ||
/** | ||
* 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 | ||
*/ | ||
export declare function preconnect(authority: string): void; | ||
//# sourceMappingURL=BrowserUtils.d.ts.map |
@@ -13,3 +13,3 @@ { | ||
}, | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"description": "Microsoft Authentication Library for js", | ||
@@ -104,4 +104,4 @@ "keywords": [ | ||
"dependencies": { | ||
"@azure/msal-common": "14.1.0" | ||
"@azure/msal-common": "14.2.0" | ||
} | ||
} |
@@ -42,3 +42,3 @@ /* | ||
const factory = new ControllerFactory(configuration); | ||
const controller = await factory.createController(); | ||
const controller = await factory.createV3Controller(); | ||
const pca = new PublicClientApplication(configuration, controller); | ||
@@ -45,0 +45,0 @@ |
@@ -96,2 +96,6 @@ /* | ||
skipAuthorityMetadataCache?: boolean; | ||
/** | ||
* App supports nested app auth or not; defaults to false | ||
*/ | ||
supportsNestedAppAuth?: boolean; | ||
}; | ||
@@ -277,2 +281,3 @@ | ||
skipAuthorityMetadataCache: false, | ||
supportsNestedAppAuth: false, | ||
}; | ||
@@ -279,0 +284,0 @@ |
@@ -28,29 +28,40 @@ /* | ||
async createController(): Promise<IController> { | ||
async createV3Controller(): Promise<IController> { | ||
const standard = new StandardOperatingContext(this.config); | ||
const metaOS = new TeamsAppOperatingContext(this.config); | ||
const operatingContexts = [standard.initialize(), metaOS.initialize()]; | ||
await standard.initialize(); | ||
return Promise.all(operatingContexts).then(async () => { | ||
if (metaOS.isAvailable()) { | ||
/* | ||
* pull down metaos module | ||
* create associated controller | ||
*/ | ||
// return await StandardController.createController(standard); | ||
const controller = await import("./StandardController"); | ||
return await controller.StandardController.createController( | ||
standard | ||
); | ||
} else if (standard.isAvailable()) { | ||
const controller = await import("./StandardController"); | ||
return await controller.StandardController.createController( | ||
standard | ||
); | ||
} | ||
const controller = await import("./StandardController"); | ||
return await controller.StandardController.createController(standard); | ||
} | ||
throw new Error("No controller found."); | ||
}); | ||
async createController(): Promise<IController | null> { | ||
const standard = new StandardOperatingContext(this.config); | ||
const teamsApp = new TeamsAppOperatingContext(this.config); | ||
const operatingContexts = [ | ||
standard.initialize(), | ||
teamsApp.initialize(), | ||
]; | ||
await Promise.all(operatingContexts); | ||
if ( | ||
teamsApp.isAvailable() && | ||
teamsApp.getConfig().auth.supportsNestedAppAuth | ||
) { | ||
const controller = await import("./NestedAppAuthController"); | ||
return await controller.NestedAppAuthController.createController( | ||
teamsApp | ||
); | ||
} else if (standard.isAvailable()) { | ||
const controller = await import("./StandardController"); | ||
return await controller.StandardController.createController( | ||
standard | ||
); | ||
} else { | ||
// Since neither of the actual operating contexts are available keep the UnknownOperatingContextController | ||
return null; | ||
} | ||
} | ||
} |
@@ -6,3 +6,2 @@ /* | ||
import { BrowserStringUtils } from "../utils/BrowserStringUtils"; | ||
import { | ||
@@ -68,3 +67,4 @@ createBrowserAuthError, | ||
); | ||
const data = BrowserStringUtils.stringToUtf8Arr(dataString); | ||
const encoder = new TextEncoder(); | ||
const data = encoder.encode(dataString); | ||
return window.crypto.subtle.digest( | ||
@@ -71,0 +71,0 @@ S256_HASH_ALG, |
@@ -18,3 +18,2 @@ /* | ||
import * as BrowserCrypto from "./BrowserCrypto"; | ||
import { BrowserStringUtils } from "../utils/BrowserStringUtils"; | ||
import { | ||
@@ -113,3 +112,3 @@ createBrowserAuthError, | ||
const publicJwkString: string = | ||
BrowserStringUtils.getSortedObjectString(pubKeyThumprintObj); | ||
getSortedObjectString(pubKeyThumprintObj); | ||
const publicJwkHash = await this.hashString(publicJwkString); | ||
@@ -185,4 +184,3 @@ | ||
); | ||
const publicKeyJwkString = | ||
BrowserStringUtils.getSortedObjectString(publicKeyJwk); | ||
const publicKeyJwkString = getSortedObjectString(publicKeyJwk); | ||
@@ -209,3 +207,4 @@ // Base64URL encode public key thumbprint with keyId only: BASE64URL({ kid: "FULL_PUBLIC_KEY_HASH" }) | ||
// Sign token | ||
const tokenBuffer = BrowserStringUtils.stringToUtf8Arr(tokenString); | ||
const encoder = new TextEncoder(); | ||
const tokenBuffer = encoder.encode(tokenString); | ||
const signatureBuffer = await BrowserCrypto.sign( | ||
@@ -240,1 +239,5 @@ cachedKeyPair.privateKey, | ||
} | ||
function getSortedObjectString(obj: object): string { | ||
return JSON.stringify(obj, Object.keys(obj).sort()); | ||
} |
@@ -11,8 +11,7 @@ /* | ||
/** | ||
* Warning: This set of exports is purely intended to be used by other MSAL libraries, and should be considered potentially unstable. We strongly discourage using them directly, you do so at your own risk. | ||
* Breaking changes to these APIs will be shipped under a minor version, instead of a major version. | ||
*/ | ||
import * as BrowserUtils from "./utils/BrowserUtils"; | ||
export { BrowserUtils }; | ||
export { PublicClientApplication } from "./app/PublicClientApplication"; | ||
export { PublicClientNext } from "./app/PublicClientNext"; | ||
export { IController } from "./controllers/IController"; | ||
@@ -36,9 +35,3 @@ export { | ||
} from "./utils/BrowserConstants"; | ||
export { BrowserUtils } from "./utils/BrowserUtils"; | ||
/* | ||
* export { IController} from "./controllers/IController"; | ||
* export { StandardController } from "./controllers/StandardController"; | ||
*/ | ||
// Browser Errors | ||
@@ -45,0 +38,0 @@ export { |
@@ -35,3 +35,3 @@ /* | ||
import { BrowserConstants } from "../utils/BrowserConstants"; | ||
import { BrowserUtils } from "../utils/BrowserUtils"; | ||
import * as BrowserUtils from "../utils/BrowserUtils"; | ||
import { INavigationClient } from "../navigation/INavigationClient"; | ||
@@ -38,0 +38,0 @@ import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler"; |
@@ -241,5 +241,6 @@ /* | ||
// fetch the account from browser cache | ||
const account = this.browserStorage.getAccountInfoFilteredBy({ | ||
const account = this.browserStorage.getBaseAccountInfo({ | ||
nativeAccountId, | ||
}); | ||
if (!account) { | ||
@@ -258,5 +259,11 @@ throw createClientAuthError(ClientAuthErrorCodes.noAccountFound); | ||
); | ||
const fullAccount = { | ||
...account, | ||
idTokenClaims: result?.idTokenClaims as TokenClaims, | ||
}; | ||
return { | ||
...result, | ||
account, | ||
account: fullAccount, | ||
}; | ||
@@ -577,2 +584,11 @@ } catch (e) { | ||
const fullAccountEntity: AccountEntity = idTokenClaims | ||
? Object.assign(new AccountEntity(), { | ||
...accountEntity, | ||
idTokenClaims: idTokenClaims, | ||
}) | ||
: accountEntity; | ||
const accountInfo = fullAccountEntity.getAccountInfo(); | ||
// generate PoP token as needed | ||
@@ -593,3 +609,3 @@ const responseAccessToken = await this.generatePopAccessToken( | ||
scopes: responseScopes.asArray(), | ||
account: accountEntity.getAccountInfo(), | ||
account: accountInfo, | ||
idToken: response.id_token, | ||
@@ -596,0 +612,0 @@ idTokenClaims: idTokenClaims, |
@@ -33,3 +33,3 @@ /* | ||
import { NavigationOptions } from "../navigation/NavigationOptions"; | ||
import { BrowserUtils } from "../utils/BrowserUtils"; | ||
import * as BrowserUtils from "../utils/BrowserUtils"; | ||
import { PopupRequest } from "../request/PopupRequest"; | ||
@@ -215,2 +215,3 @@ import { NativeInteractionClient } from "./NativeInteractionClient"; | ||
); | ||
BrowserUtils.preconnect(validRequest.authority); | ||
this.browserStorage.updateCacheEntries( | ||
@@ -217,0 +218,0 @@ validRequest.state, |
@@ -29,3 +29,3 @@ /* | ||
import { RedirectHandler } from "../interaction_handler/RedirectHandler"; | ||
import { BrowserUtils } from "../utils/BrowserUtils"; | ||
import * as BrowserUtils from "../utils/BrowserUtils"; | ||
import { EndSessionRequest } from "../request/EndSessionRequest"; | ||
@@ -32,0 +32,0 @@ import { EventType } from "../event/EventType"; |
@@ -27,3 +27,2 @@ /* | ||
import { InteractionType, ApiId } from "../utils/BrowserConstants"; | ||
import { SilentHandler } from "../interaction_handler/SilentHandler"; | ||
import { AuthorizationCodeRequest } from "../request/AuthorizationCodeRequest"; | ||
@@ -33,2 +32,3 @@ import { HybridSpaAuthorizationCodeClient } from "./HybridSpaAuthorizationCodeClient"; | ||
import { AuthenticationResult } from "../response/AuthenticationResult"; | ||
import { InteractionHandler } from "../interaction_handler/InteractionHandler"; | ||
@@ -118,3 +118,3 @@ export class SilentAuthCodeClient extends StandardInteractionClient { | ||
// Create silent handler | ||
const silentHandler = new SilentHandler( | ||
const interactionHandler = new InteractionHandler( | ||
authClient, | ||
@@ -124,3 +124,2 @@ this.browserStorage, | ||
this.logger, | ||
this.config.system, | ||
this.performanceClient | ||
@@ -131,3 +130,5 @@ ); | ||
return invokeAsync( | ||
silentHandler.handleCodeResponseFromServer.bind(silentHandler), | ||
interactionHandler.handleCodeResponseFromServer.bind( | ||
interactionHandler | ||
), | ||
PerformanceEvents.HandleCodeResponseFromServer, | ||
@@ -134,0 +135,0 @@ this.logger, |
@@ -33,2 +33,6 @@ /* | ||
): Promise<AuthenticationResult> { | ||
this.performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentCacheClientAcquireToken, | ||
silentRequest.correlationId | ||
); | ||
// Telemetry manager only used to increment cacheHits here | ||
@@ -47,5 +51,9 @@ const serverTelemetryManager = this.initializeServerTelemetryManager( | ||
try { | ||
const response = await silentAuthClient.acquireCachedToken( | ||
silentRequest | ||
); | ||
const response = await invokeAsync( | ||
silentAuthClient.acquireCachedToken.bind(silentAuthClient), | ||
PerformanceEvents.SilentFlowClientAcquireCachedToken, | ||
this.logger, | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
)(silentRequest); | ||
const authResponse = response[0] as AuthenticationResult; | ||
@@ -52,0 +60,0 @@ |
@@ -32,3 +32,6 @@ /* | ||
import { InteractionType, ApiId } from "../utils/BrowserConstants"; | ||
import { SilentHandler } from "../interaction_handler/SilentHandler"; | ||
import { | ||
initiateAuthRequest, | ||
monitorIframeForHash, | ||
} from "../interaction_handler/SilentHandler"; | ||
import { SsoSilentRequest } from "../request/SsoSilentRequest"; | ||
@@ -38,2 +41,4 @@ import { NativeMessageHandler } from "../broker/nativeBroker/NativeMessageHandler"; | ||
import { AuthenticationResult } from "../response/AuthenticationResult"; | ||
import { InteractionHandler } from "../interaction_handler/InteractionHandler"; | ||
import * as BrowserUtils from "../utils/BrowserUtils"; | ||
@@ -119,2 +124,3 @@ export class SilentIframeClient extends StandardInteractionClient { | ||
); | ||
BrowserUtils.preconnect(silentRequest.authority); | ||
this.browserStorage.updateCacheEntries( | ||
@@ -185,5 +191,6 @@ silentRequest.state, | ||
): Promise<AuthenticationResult> { | ||
const correlationId = silentRequest.correlationId; | ||
this.performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentIframeClientTokenHelper, | ||
silentRequest.correlationId | ||
correlationId | ||
); | ||
@@ -198,3 +205,3 @@ | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
correlationId | ||
)(silentRequest); | ||
@@ -208,3 +215,3 @@ | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
correlationId | ||
)({ | ||
@@ -221,3 +228,3 @@ ...silentRequest, | ||
// Create silent handler | ||
const silentHandler = new SilentHandler( | ||
const interactionHandler = new InteractionHandler( | ||
authClient, | ||
@@ -227,3 +234,2 @@ this.browserStorage, | ||
this.logger, | ||
this.config.system, | ||
this.performanceClient | ||
@@ -233,16 +239,44 @@ ); | ||
const msalFrame = await invokeAsync( | ||
silentHandler.initiateAuthRequest.bind(silentHandler), | ||
initiateAuthRequest, | ||
PerformanceEvents.SilentHandlerInitiateAuthRequest, | ||
this.logger, | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
)(navigateUrl); | ||
correlationId | ||
)( | ||
navigateUrl, | ||
this.performanceClient, | ||
this.logger, | ||
correlationId, | ||
this.config.system.navigateFrameWait | ||
); | ||
// Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds. | ||
const hash = await invokeAsync( | ||
silentHandler.monitorIframeForHash.bind(silentHandler), | ||
monitorIframeForHash, | ||
PerformanceEvents.SilentHandlerMonitorIframeForHash, | ||
this.logger, | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
)(msalFrame, this.config.system.iframeHashTimeout); | ||
correlationId | ||
)( | ||
msalFrame, | ||
this.config.system.iframeHashTimeout, | ||
this.config.system.pollIntervalMilliseconds, | ||
this.performanceClient, | ||
this.logger, | ||
correlationId | ||
); | ||
if (!hash) { | ||
// No hash is present | ||
this.logger.error( | ||
"The request has returned to the redirectUri but a hash is not present in the iframe. It's likely that the hash has been removed or the page has been redirected by code running on the redirectUri page." | ||
); | ||
throw createBrowserAuthError(BrowserAuthErrorCodes.hashEmptyError); | ||
} else if (!UrlString.hashContainsKnownProperties(hash)) { | ||
this.logger.error( | ||
"A hash is present in the iframe but it does not contain known properties. It's likely that the hash has been replaced by code running on the redirectUri page." | ||
); | ||
this.logger.errorPii(`The hash detected in the iframe is: ${hash}`); | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.hashDoesNotContainKnownProperties | ||
); | ||
} | ||
// Deserialize hash fragment response parameters. | ||
@@ -254,3 +288,3 @@ const serverParams: ServerAuthorizationCodeResponse = | ||
InteractionType.Silent, | ||
authCodeRequest.correlationId | ||
correlationId | ||
); | ||
@@ -279,3 +313,3 @@ | ||
this.browserStorage, | ||
this.correlationId | ||
correlationId | ||
); | ||
@@ -293,3 +327,3 @@ const { userRequestState } = ProtocolUtils.parseRequestState( | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
correlationId | ||
)({ | ||
@@ -306,9 +340,11 @@ ...silentRequest, | ||
return invokeAsync( | ||
silentHandler.handleCodeResponseFromHash.bind(silentHandler), | ||
interactionHandler.handleCodeResponseFromHash.bind( | ||
interactionHandler | ||
), | ||
PerformanceEvents.HandleCodeResponseFromHash, | ||
this.logger, | ||
this.performanceClient, | ||
silentRequest.correlationId | ||
correlationId | ||
)(hash, state, authClient.authority, this.networkClient); | ||
} | ||
} |
@@ -40,3 +40,3 @@ /* | ||
import { EndSessionRequest } from "../request/EndSessionRequest"; | ||
import { BrowserUtils } from "../utils/BrowserUtils"; | ||
import * as BrowserUtils from "../utils/BrowserUtils"; | ||
import { RedirectRequest } from "../request/RedirectRequest"; | ||
@@ -43,0 +43,0 @@ import { PopupRequest } from "../request/PopupRequest"; |
@@ -7,6 +7,2 @@ /* | ||
import { | ||
UrlString, | ||
CommonAuthorizationCodeRequest, | ||
AuthorizationCodeClient, | ||
Constants, | ||
Logger, | ||
@@ -16,4 +12,4 @@ IPerformanceClient, | ||
invokeAsync, | ||
invoke, | ||
} from "@azure/msal-common"; | ||
import { InteractionHandler } from "./InteractionHandler"; | ||
import { | ||
@@ -23,250 +19,198 @@ createBrowserAuthError, | ||
} from "../error/BrowserAuthError"; | ||
import { BrowserCacheManager } from "../cache/BrowserCacheManager"; | ||
import { | ||
BrowserSystemOptions, | ||
DEFAULT_IFRAME_TIMEOUT_MS, | ||
} from "../config/Configuration"; | ||
import { DEFAULT_IFRAME_TIMEOUT_MS } from "../config/Configuration"; | ||
export class SilentHandler extends InteractionHandler { | ||
private navigateFrameWait: number; | ||
private pollIntervalMilliseconds: number; | ||
/** | ||
* 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<HTMLIFrameElement> { | ||
performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentHandlerInitiateAuthRequest, | ||
correlationId | ||
); | ||
constructor( | ||
authCodeModule: AuthorizationCodeClient, | ||
storageImpl: BrowserCacheManager, | ||
authCodeRequest: CommonAuthorizationCodeRequest, | ||
logger: Logger, | ||
systemOptions: Required< | ||
Pick< | ||
BrowserSystemOptions, | ||
"navigateFrameWait" | "pollIntervalMilliseconds" | ||
> | ||
>, | ||
performanceClient: IPerformanceClient | ||
) { | ||
super( | ||
authCodeModule, | ||
storageImpl, | ||
authCodeRequest, | ||
if (!requestUrl) { | ||
// Throw error if request URL is empty. | ||
logger.info("Navigate url is empty"); | ||
throw createBrowserAuthError(BrowserAuthErrorCodes.emptyNavigateUri); | ||
} | ||
if (navigateFrameWait) { | ||
return await invokeAsync( | ||
loadFrame, | ||
PerformanceEvents.SilentHandlerLoadFrame, | ||
logger, | ||
performanceClient | ||
); | ||
this.navigateFrameWait = systemOptions.navigateFrameWait; | ||
this.pollIntervalMilliseconds = systemOptions.pollIntervalMilliseconds; | ||
performanceClient, | ||
correlationId | ||
)(requestUrl, navigateFrameWait, performanceClient, correlationId); | ||
} | ||
return invoke( | ||
loadFrameSync, | ||
PerformanceEvents.SilentHandlerLoadFrameSync, | ||
logger, | ||
performanceClient, | ||
correlationId | ||
)(requestUrl); | ||
} | ||
/** | ||
* Creates a hidden iframe to given URL using user-requested scopes as an id. | ||
* @param urlNavigate | ||
* @param userRequestScopes | ||
*/ | ||
async initiateAuthRequest(requestUrl: string): Promise<HTMLIFrameElement> { | ||
this.performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentHandlerInitiateAuthRequest, | ||
this.authCodeRequest.correlationId | ||
); | ||
/** | ||
* 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 | ||
): Promise<string> { | ||
performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentHandlerMonitorIframeForHash, | ||
correlationId | ||
); | ||
if (!requestUrl) { | ||
// Throw error if request URL is empty. | ||
this.logger.info("Navigate url is empty"); | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.emptyNavigateUri | ||
return new Promise<string>((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.` | ||
); | ||
} | ||
if (this.navigateFrameWait) { | ||
return await invokeAsync( | ||
this.loadFrame.bind(this), | ||
PerformanceEvents.SilentHandlerLoadFrame, | ||
this.logger, | ||
this.performanceClient, | ||
this.authCodeRequest.correlationId | ||
)(requestUrl); | ||
} | ||
return this.loadFrameSync(requestUrl); | ||
} | ||
/* | ||
* 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); | ||
/** | ||
* Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout. | ||
* @param iframe | ||
* @param timeout | ||
*/ | ||
monitorIframeForHash( | ||
iframe: HTMLIFrameElement, | ||
timeout: number | ||
): Promise<string> { | ||
this.performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentHandlerMonitorIframeForHash, | ||
this.authCodeRequest.correlationId | ||
); | ||
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) {} | ||
return new Promise((resolve, reject) => { | ||
if (timeout < DEFAULT_IFRAME_TIMEOUT_MS) { | ||
this.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.` | ||
); | ||
if (!href || href === "about:blank") { | ||
return; | ||
} | ||
/* | ||
* Polling for iframes can be purely timing based, | ||
* since we don't need to account for interaction. | ||
*/ | ||
const nowMark = window.performance.now(); | ||
const timeoutMark = nowMark + timeout; | ||
const contentHash = contentWindow | ||
? contentWindow.location.hash | ||
: ""; | ||
window.clearTimeout(timeoutId); | ||
window.clearInterval(intervalId); | ||
resolve(contentHash); | ||
}, pollIntervalMilliseconds); | ||
}).finally(() => { | ||
invoke( | ||
removeHiddenIframe, | ||
PerformanceEvents.RemoveHiddenIframe, | ||
logger, | ||
performanceClient, | ||
correlationId | ||
)(iframe); | ||
}); | ||
} | ||
const intervalId = setInterval(() => { | ||
if (window.performance.now() > timeoutMark) { | ||
this.removeHiddenIframe(iframe); | ||
clearInterval(intervalId); | ||
reject( | ||
createBrowserAuthError( | ||
BrowserAuthErrorCodes.monitorWindowTimeout | ||
) | ||
); | ||
return; | ||
} | ||
/** | ||
* @hidden | ||
* Loads iframe with authorization endpoint URL | ||
* @ignore | ||
* @deprecated | ||
*/ | ||
function loadFrame( | ||
urlNavigate: string, | ||
navigateFrameWait: number, | ||
performanceClient: IPerformanceClient, | ||
correlationId: string | ||
): Promise<HTMLIFrameElement> { | ||
performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentHandlerLoadFrame, | ||
correlationId | ||
); | ||
let href: string = Constants.EMPTY_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 | ||
: Constants.EMPTY_STRING; | ||
} catch (e) {} | ||
if (!href || href === "about:blank") { | ||
return; | ||
} | ||
const contentHash = contentWindow | ||
? contentWindow.location.hash | ||
: Constants.EMPTY_STRING; | ||
if (contentHash) { | ||
if (UrlString.hashContainsKnownProperties(contentHash)) { | ||
// Success case | ||
this.removeHiddenIframe(iframe); | ||
clearInterval(intervalId); | ||
resolve(contentHash); | ||
return; | ||
} else { | ||
// Hash is present but incorrect | ||
this.logger.error( | ||
"SilentHandler:monitorIFrameForHash - a hash is present in the iframe but it does not contain known properties. It's likely that the hash has been replaced by code running on the redirectUri page." | ||
); | ||
this.logger.errorPii( | ||
`SilentHandler:monitorIFrameForHash - the url detected in the iframe is: ${href}` | ||
); | ||
this.removeHiddenIframe(iframe); | ||
clearInterval(intervalId); | ||
reject( | ||
createBrowserAuthError( | ||
BrowserAuthErrorCodes.hashDoesNotContainKnownProperties | ||
) | ||
); | ||
return; | ||
} | ||
} else { | ||
// No hash is present | ||
this.logger.error( | ||
"SilentHandler:monitorIFrameForHash - the request has returned to the redirectUri but a hash is not present in the iframe. It's likely that the hash has been removed or the page has been redirected by code running on the redirectUri page." | ||
); | ||
this.logger.errorPii( | ||
`SilentHandler:monitorIFrameForHash - the url detected in the iframe is: ${href}` | ||
); | ||
this.removeHiddenIframe(iframe); | ||
clearInterval(intervalId); | ||
reject( | ||
createBrowserAuthError( | ||
BrowserAuthErrorCodes.hashEmptyError | ||
) | ||
); | ||
return; | ||
} | ||
}, this.pollIntervalMilliseconds); | ||
}); | ||
} | ||
/** | ||
* @hidden | ||
* Loads iframe with authorization endpoint URL | ||
* @ignore | ||
/* | ||
* This trick overcomes iframe navigation in IE | ||
* IE does not load the page consistently in iframe | ||
*/ | ||
private loadFrame(urlNavigate: string): Promise<HTMLIFrameElement> { | ||
this.performanceClient.addQueueMeasurement( | ||
PerformanceEvents.SilentHandlerLoadFrame, | ||
this.authCodeRequest.correlationId | ||
); | ||
/* | ||
* This trick overcomes iframe navigation in IE | ||
* IE does not load the page consistently in iframe | ||
*/ | ||
return new Promise((resolve, reject) => { | ||
const frameHandle = createHiddenIframe(); | ||
return new Promise((resolve, reject) => { | ||
const frameHandle = this.createHiddenIframe(); | ||
window.setTimeout(() => { | ||
if (!frameHandle) { | ||
reject("Unable to load iframe"); | ||
return; | ||
} | ||
setTimeout(() => { | ||
if (!frameHandle) { | ||
reject("Unable to load iframe"); | ||
return; | ||
} | ||
frameHandle.src = urlNavigate; | ||
frameHandle.src = urlNavigate; | ||
resolve(frameHandle); | ||
}, navigateFrameWait); | ||
}); | ||
} | ||
/** | ||
* @hidden | ||
* Loads the iframe synchronously when the navigateTimeFrame is set to `0` | ||
* @param urlNavigate | ||
* @param frameName | ||
* @param logger | ||
*/ | ||
function loadFrameSync(urlNavigate: string): HTMLIFrameElement { | ||
const frameHandle = createHiddenIframe(); | ||
resolve(frameHandle); | ||
}, this.navigateFrameWait); | ||
}); | ||
} | ||
frameHandle.src = urlNavigate; | ||
/** | ||
* @hidden | ||
* Loads the iframe synchronously when the navigateTimeFrame is set to `0` | ||
* @param urlNavigate | ||
* @param frameName | ||
* @param logger | ||
*/ | ||
private loadFrameSync(urlNavigate: string): HTMLIFrameElement { | ||
const frameHandle = this.createHiddenIframe(); | ||
return frameHandle; | ||
} | ||
frameHandle.src = urlNavigate; | ||
/** | ||
* @hidden | ||
* Creates a new hidden iframe or gets an existing one for silent token renewal. | ||
* @ignore | ||
*/ | ||
function createHiddenIframe(): HTMLIFrameElement { | ||
const authFrame = document.createElement("iframe"); | ||
return frameHandle; | ||
} | ||
authFrame.style.visibility = "hidden"; | ||
authFrame.style.position = "absolute"; | ||
authFrame.style.width = authFrame.style.height = "0"; | ||
authFrame.style.border = "0"; | ||
authFrame.setAttribute( | ||
"sandbox", | ||
"allow-scripts allow-same-origin allow-forms" | ||
); | ||
document.getElementsByTagName("body")[0].appendChild(authFrame); | ||
/** | ||
* @hidden | ||
* Creates a new hidden iframe or gets an existing one for silent token renewal. | ||
* @ignore | ||
*/ | ||
private createHiddenIframe(): HTMLIFrameElement { | ||
const authFrame = document.createElement("iframe"); | ||
return authFrame; | ||
} | ||
authFrame.style.visibility = "hidden"; | ||
authFrame.style.position = "absolute"; | ||
authFrame.style.width = authFrame.style.height = "0"; | ||
authFrame.style.border = "0"; | ||
authFrame.setAttribute( | ||
"sandbox", | ||
"allow-scripts allow-same-origin allow-forms" | ||
); | ||
document.getElementsByTagName("body")[0].appendChild(authFrame); | ||
return authFrame; | ||
/** | ||
* @hidden | ||
* Removes a hidden iframe from the page. | ||
* @ignore | ||
*/ | ||
function removeHiddenIframe(iframe: HTMLIFrameElement): void { | ||
if (document.body === iframe.parentNode) { | ||
document.body.removeChild(iframe); | ||
} | ||
/** | ||
* @hidden | ||
* Removes a hidden iframe from the page. | ||
* @ignore | ||
*/ | ||
private removeHiddenIframe(iframe: HTMLIFrameElement): void { | ||
if (document.body === iframe.parentNode) { | ||
document.body.removeChild(iframe); | ||
} | ||
} | ||
} |
@@ -7,4 +7,10 @@ /* | ||
import { BaseOperatingContext } from "./BaseOperatingContext"; | ||
import { IBridgeProxy } from "../naa/IBridgeProxy"; | ||
import { BridgeProxy } from "../naa/BridgeProxy"; | ||
import { AccountInfo } from "../naa/AccountInfo"; | ||
export class TeamsAppOperatingContext extends BaseOperatingContext { | ||
protected bridgeProxy: IBridgeProxy | undefined = undefined; | ||
protected activeAccount: AccountInfo | undefined = undefined; | ||
/* | ||
@@ -37,2 +43,14 @@ * TODO: Once we have determine the bundling code return here to specify the name of the bundle | ||
getBridgeProxy(): IBridgeProxy | undefined { | ||
return this.bridgeProxy; | ||
} | ||
getActiveAccount(): AccountInfo | undefined { | ||
return this.activeAccount; | ||
} | ||
setActiveAccount(account: AccountInfo): void { | ||
this.activeAccount = account; | ||
} | ||
/** | ||
@@ -45,7 +63,29 @@ * Checks whether the operating context is available. | ||
/* | ||
* TODO: Add implementation to check for presence of inject MetaOSHub JavaScript interface | ||
* TODO: Make pre-flight token request to ensure that App is eligible to use Nested App Auth | ||
* TODO: Add implementation to check for presence of inject Nested App Auth Bridge JavaScript interface | ||
* | ||
*/ | ||
return false; | ||
try { | ||
if (typeof window !== "undefined") { | ||
const bridgeProxy: IBridgeProxy = await BridgeProxy.create(); | ||
/* | ||
* Because we want single sign on we need to attempt to | ||
* grab the active account as part of initialization | ||
* this.activeAccount = await bridgeProxy.getActiveAccount(); | ||
*/ | ||
try { | ||
this.activeAccount = await bridgeProxy.getActiveAccount(); | ||
} catch (e) { | ||
this.activeAccount = undefined; | ||
} | ||
this.bridgeProxy = bridgeProxy; | ||
this.available = bridgeProxy !== undefined; | ||
} else { | ||
this.available = false; | ||
} | ||
} catch (e) { | ||
this.available = false; | ||
} finally { | ||
return this.available; | ||
} | ||
} | ||
} |
/* eslint-disable header/header */ | ||
export const name = "@azure/msal-browser"; | ||
export const version = "3.2.0"; | ||
export const version = "3.3.0"; |
@@ -6,3 +6,3 @@ /* | ||
import { Constants, UrlString } from "@azure/msal-common"; | ||
import { UrlString } from "@azure/msal-common"; | ||
import { | ||
@@ -15,144 +15,152 @@ createBrowserAuthError, | ||
/** | ||
* Utility class for browser specific functions | ||
* Clears hash from window url. | ||
*/ | ||
export class BrowserUtils { | ||
// #region Window Navigation and URL management | ||
/** | ||
* Clears hash from window url. | ||
*/ | ||
static clearHash(contentWindow: Window): void { | ||
// Office.js sets history.replaceState to null | ||
contentWindow.location.hash = Constants.EMPTY_STRING; | ||
if (typeof contentWindow.history.replaceState === "function") { | ||
// Full removes "#" from url | ||
contentWindow.history.replaceState( | ||
null, | ||
Constants.EMPTY_STRING, | ||
`${contentWindow.location.origin}${contentWindow.location.pathname}${contentWindow.location.search}` | ||
); | ||
} | ||
export function clearHash(contentWindow: Window): void { | ||
// 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 | ||
*/ | ||
static replaceHash(url: string): void { | ||
const urlParts = url.split("#"); | ||
urlParts.shift(); // Remove part before the hash | ||
window.location.hash = | ||
urlParts.length > 0 ? urlParts.join("#") : Constants.EMPTY_STRING; | ||
} | ||
/** | ||
* Replaces current hash with hash from provided url | ||
*/ | ||
export function replaceHash(url: string): void { | ||
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. | ||
*/ | ||
static isInIframe(): boolean { | ||
return window.parent !== window; | ||
} | ||
/** | ||
* Returns boolean of whether the current window is in an iframe or not. | ||
*/ | ||
export function isInIframe(): boolean { | ||
return window.parent !== window; | ||
} | ||
/** | ||
* Returns boolean of whether or not the current window is a popup opened by msal | ||
*/ | ||
static isInPopup(): boolean { | ||
return ( | ||
typeof window !== "undefined" && | ||
!!window.opener && | ||
window.opener !== window && | ||
typeof window.name === "string" && | ||
window.name.indexOf(`${BrowserConstants.POPUP_NAME_PREFIX}.`) === 0 | ||
); | ||
} | ||
/** | ||
* Returns boolean of whether or not the current window is a popup opened by msal | ||
*/ | ||
export function isInPopup(): boolean { | ||
return ( | ||
typeof window !== "undefined" && | ||
!!window.opener && | ||
window.opener !== window && | ||
typeof window.name === "string" && | ||
window.name.indexOf(`${BrowserConstants.POPUP_NAME_PREFIX}.`) === 0 | ||
); | ||
} | ||
// #endregion | ||
// #endregion | ||
/** | ||
* Returns current window URL as redirect uri | ||
*/ | ||
static getCurrentUri(): string { | ||
return window.location.href.split("?")[0].split("#")[0]; | ||
} | ||
/** | ||
* Returns current window URL as redirect uri | ||
*/ | ||
export function getCurrentUri(): string { | ||
return window.location.href.split("?")[0].split("#")[0]; | ||
} | ||
/** | ||
* Gets the homepage url for the current window location. | ||
*/ | ||
static getHomepage(): string { | ||
const currentUrl = new UrlString(window.location.href); | ||
const urlComponents = currentUrl.getUrlComponents(); | ||
return `${urlComponents.Protocol}//${urlComponents.HostNameAndPort}/`; | ||
} | ||
/** | ||
* Gets the homepage url for the current window location. | ||
*/ | ||
export function getHomepage(): string { | ||
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. | ||
*/ | ||
static blockReloadInHiddenIframes(): void { | ||
const isResponseHash = UrlString.hashContainsKnownProperties( | ||
window.location.hash | ||
); | ||
// return an error if called from the hidden iframe created by the msal js silent calls | ||
if (isResponseHash && BrowserUtils.isInIframe()) { | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.blockIframeReload | ||
); | ||
} | ||
/** | ||
* Throws error if we have completed an auth and are | ||
* attempting another auth request inside an iframe. | ||
*/ | ||
export function blockReloadInHiddenIframes(): void { | ||
const isResponseHash = UrlString.hashContainsKnownProperties( | ||
window.location.hash | ||
); | ||
// return an error if called from the hidden iframe created by the msal js silent calls | ||
if (isResponseHash && isInIframe()) { | ||
throw createBrowserAuthError(BrowserAuthErrorCodes.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 | ||
*/ | ||
static blockRedirectInIframe( | ||
interactionType: InteractionType, | ||
allowRedirectInIframe: boolean | ||
): void { | ||
const isIframedApp = BrowserUtils.isInIframe(); | ||
if ( | ||
interactionType === InteractionType.Redirect && | ||
isIframedApp && | ||
!allowRedirectInIframe | ||
) { | ||
// If we are not in top frame, we shouldn't redirect. This is also handled by the service. | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.redirectInIframe | ||
); | ||
} | ||
/** | ||
* 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 | ||
*/ | ||
export function blockRedirectInIframe( | ||
interactionType: InteractionType, | ||
allowRedirectInIframe: boolean | ||
): void { | ||
const isIframedApp = isInIframe(); | ||
if ( | ||
interactionType === InteractionType.Redirect && | ||
isIframedApp && | ||
!allowRedirectInIframe | ||
) { | ||
// If we are not in top frame, we shouldn't redirect. This is also handled by the service. | ||
throw createBrowserAuthError(BrowserAuthErrorCodes.redirectInIframe); | ||
} | ||
} | ||
/** | ||
* Block redirectUri loaded in popup from calling AcquireToken APIs | ||
*/ | ||
static blockAcquireTokenInPopups(): void { | ||
// Popups opened by msal popup APIs are given a name that starts with "msal." | ||
if (BrowserUtils.isInPopup()) { | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.blockNestedPopups | ||
); | ||
} | ||
/** | ||
* Block redirectUri loaded in popup from calling AcquireToken APIs | ||
*/ | ||
export function blockAcquireTokenInPopups(): void { | ||
// Popups opened by msal popup APIs are given a name that starts with "msal." | ||
if (isInPopup()) { | ||
throw createBrowserAuthError(BrowserAuthErrorCodes.blockNestedPopups); | ||
} | ||
} | ||
/** | ||
* Throws error if token requests are made in non-browser environment | ||
* @param isBrowserEnvironment Flag indicating if environment is a browser. | ||
*/ | ||
static blockNonBrowserEnvironment(isBrowserEnvironment: boolean): void { | ||
if (!isBrowserEnvironment) { | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.nonBrowserEnvironment | ||
); | ||
} | ||
/** | ||
* Throws error if token requests are made in non-browser environment | ||
* @param isBrowserEnvironment Flag indicating if environment is a browser. | ||
*/ | ||
export function blockNonBrowserEnvironment( | ||
isBrowserEnvironment: boolean | ||
): void { | ||
if (!isBrowserEnvironment) { | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.nonBrowserEnvironment | ||
); | ||
} | ||
} | ||
/** | ||
* Throws error if initialize hasn't been called | ||
* @param initialized | ||
*/ | ||
static blockAPICallsBeforeInitialize(initialized: boolean): void { | ||
if (!initialized) { | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.uninitializedPublicClientApplication | ||
); | ||
} | ||
/** | ||
* Throws error if initialize hasn't been called | ||
* @param initialized | ||
*/ | ||
export function blockAPICallsBeforeInitialize(initialized: boolean): void { | ||
if (!initialized) { | ||
throw createBrowserAuthError( | ||
BrowserAuthErrorCodes.uninitializedPublicClientApplication | ||
); | ||
} | ||
} | ||
/** | ||
* 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 | ||
*/ | ||
export function preconnect(authority: string): void { | ||
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 | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
413
6
3390426
51074
+ Added@azure/msal-common@14.2.0(transitive)
- Removed@azure/msal-common@14.1.0(transitive)
Updated@azure/msal-common@14.2.0