`.\r\n * @returns {Function} A `useDispatch` hook bound to the specified context.\r\n */\n\nexport function createDispatchHook(context) {\n if (context === void 0) {\n context = ReactReduxContext;\n }\n\n var useStore = context === ReactReduxContext ? useDefaultStore : createStoreHook(context);\n return function useDispatch() {\n var store = useStore();\n return store.dispatch;\n };\n}\n/**\r\n * A hook to access the redux `dispatch` function.\r\n *\r\n * @returns {any|function} redux store's `dispatch` function\r\n *\r\n * @example\r\n *\r\n * import React, { useCallback } from 'react'\r\n * import { useDispatch } from 'react-redux'\r\n *\r\n * export const CounterComponent = ({ value }) => {\r\n * const dispatch = useDispatch()\r\n * const increaseCounter = useCallback(() => dispatch({ type: 'increase-counter' }), [])\r\n * return (\r\n * \r\n * {value}\r\n * \r\n *
\r\n * )\r\n * }\r\n */\n\nexport var useDispatch = /*#__PURE__*/createDispatchHook();","import { useReducer, useRef, useMemo, useContext, useDebugValue } from 'react';\nimport { useReduxContext as useDefaultReduxContext } from './useReduxContext';\nimport Subscription from '../utils/Subscription';\nimport { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect';\nimport { ReactReduxContext } from '../components/Context';\n\nvar refEquality = function refEquality(a, b) {\n return a === b;\n};\n\nfunction useSelectorWithStoreAndSubscription(selector, equalityFn, store, contextSub) {\n var _useReducer = useReducer(function (s) {\n return s + 1;\n }, 0),\n forceRender = _useReducer[1];\n\n var subscription = useMemo(function () {\n return new Subscription(store, contextSub);\n }, [store, contextSub]);\n var latestSubscriptionCallbackError = useRef();\n var latestSelector = useRef();\n var latestStoreState = useRef();\n var latestSelectedState = useRef();\n var storeState = store.getState();\n var selectedState;\n\n try {\n if (selector !== latestSelector.current || storeState !== latestStoreState.current || latestSubscriptionCallbackError.current) {\n var newSelectedState = selector(storeState); // ensure latest selected state is reused so that a custom equality function can result in identical references\n\n if (latestSelectedState.current === undefined || !equalityFn(newSelectedState, latestSelectedState.current)) {\n selectedState = newSelectedState;\n } else {\n selectedState = latestSelectedState.current;\n }\n } else {\n selectedState = latestSelectedState.current;\n }\n } catch (err) {\n if (latestSubscriptionCallbackError.current) {\n err.message += \"\\nThe error may be correlated with this previous error:\\n\" + latestSubscriptionCallbackError.current.stack + \"\\n\\n\";\n }\n\n throw err;\n }\n\n useIsomorphicLayoutEffect(function () {\n latestSelector.current = selector;\n latestStoreState.current = storeState;\n latestSelectedState.current = selectedState;\n latestSubscriptionCallbackError.current = undefined;\n });\n useIsomorphicLayoutEffect(function () {\n function checkForUpdates() {\n try {\n var newStoreState = store.getState();\n\n var _newSelectedState = latestSelector.current(newStoreState);\n\n if (equalityFn(_newSelectedState, latestSelectedState.current)) {\n return;\n }\n\n latestSelectedState.current = _newSelectedState;\n latestStoreState.current = newStoreState;\n } catch (err) {\n // we ignore all errors here, since when the component\n // is re-rendered, the selectors are called again, and\n // will throw again, if neither props nor store state\n // changed\n latestSubscriptionCallbackError.current = err;\n }\n\n forceRender();\n }\n\n subscription.onStateChange = checkForUpdates;\n subscription.trySubscribe();\n checkForUpdates();\n return function () {\n return subscription.tryUnsubscribe();\n };\n }, [store, subscription]);\n return selectedState;\n}\n/**\r\n * Hook factory, which creates a `useSelector` hook bound to a given context.\r\n *\r\n * @param {React.Context} [context=ReactReduxContext] Context passed to your ``.\r\n * @returns {Function} A `useSelector` hook bound to the specified context.\r\n */\n\n\nexport function createSelectorHook(context) {\n if (context === void 0) {\n context = ReactReduxContext;\n }\n\n var useReduxContext = context === ReactReduxContext ? useDefaultReduxContext : function () {\n return useContext(context);\n };\n return function useSelector(selector, equalityFn) {\n if (equalityFn === void 0) {\n equalityFn = refEquality;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n if (!selector) {\n throw new Error(\"You must pass a selector to useSelector\");\n }\n\n if (typeof selector !== 'function') {\n throw new Error(\"You must pass a function as a selector to useSelector\");\n }\n\n if (typeof equalityFn !== 'function') {\n throw new Error(\"You must pass a function as an equality function to useSelector\");\n }\n }\n\n var _useReduxContext = useReduxContext(),\n store = _useReduxContext.store,\n contextSub = _useReduxContext.subscription;\n\n var selectedState = useSelectorWithStoreAndSubscription(selector, equalityFn, store, contextSub);\n useDebugValue(selectedState);\n return selectedState;\n };\n}\n/**\r\n * A hook to access the redux store's state. This hook takes a selector function\r\n * as an argument. The selector is called with the store state.\r\n *\r\n * This hook takes an optional equality comparison function as the second parameter\r\n * that allows you to customize the way the selected state is compared to determine\r\n * whether the component needs to be re-rendered.\r\n *\r\n * @param {Function} selector the selector function\r\n * @param {Function=} equalityFn the function that will be used to determine equality\r\n *\r\n * @returns {any} the selected state\r\n *\r\n * @example\r\n *\r\n * import React from 'react'\r\n * import { useSelector } from 'react-redux'\r\n *\r\n * export const CounterComponent = () => {\r\n * const counter = useSelector(state => state.counter)\r\n * return {counter}
\r\n * }\r\n */\n\nexport var useSelector = /*#__PURE__*/createSelectorHook();","import Provider from './components/Provider';\nimport connectAdvanced from './components/connectAdvanced';\nimport { ReactReduxContext } from './components/Context';\nimport connect from './connect/connect';\nimport { useDispatch, createDispatchHook } from './hooks/useDispatch';\nimport { useSelector, createSelectorHook } from './hooks/useSelector';\nimport { useStore, createStoreHook } from './hooks/useStore';\nimport { setBatch } from './utils/batch';\nimport { unstable_batchedUpdates as batch } from './utils/reactBatchedUpdates';\nimport shallowEqual from './utils/shallowEqual';\nsetBatch(batch);\nexport { Provider, connectAdvanced, ReactReduxContext, connect, batch, useDispatch, createDispatchHook, useSelector, createSelectorHook, useStore, createStoreHook, shallowEqual };","/** @license React v16.14.0\n * react-jsx-runtime.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n'use strict';var f=require(\"react\"),g=60103;exports.Fragment=60107;if(\"function\"===typeof Symbol&&Symbol.for){var h=Symbol.for;g=h(\"react.element\");exports.Fragment=h(\"react.fragment\")}var m=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,n=Object.prototype.hasOwnProperty,p={key:!0,ref:!0,__self:!0,__source:!0};\nfunction q(c,a,k){var b,d={},e=null,l=null;void 0!==k&&(e=\"\"+k);void 0!==a.key&&(e=\"\"+a.key);void 0!==a.ref&&(l=a.ref);for(b in a)n.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return{$$typeof:g,type:c,key:e,ref:l,props:d,_owner:m.current}}exports.jsx=q;exports.jsxs=q;\n","/** @license React v16.14.0\n * react.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';var l=require(\"object-assign\"),n=\"function\"===typeof Symbol&&Symbol.for,p=n?Symbol.for(\"react.element\"):60103,q=n?Symbol.for(\"react.portal\"):60106,r=n?Symbol.for(\"react.fragment\"):60107,t=n?Symbol.for(\"react.strict_mode\"):60108,u=n?Symbol.for(\"react.profiler\"):60114,v=n?Symbol.for(\"react.provider\"):60109,w=n?Symbol.for(\"react.context\"):60110,x=n?Symbol.for(\"react.forward_ref\"):60112,y=n?Symbol.for(\"react.suspense\"):60113,z=n?Symbol.for(\"react.memo\"):60115,A=n?Symbol.for(\"react.lazy\"):\n60116,B=\"function\"===typeof Symbol&&Symbol.iterator;function C(a){for(var b=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+a,c=1;cQ.length&&Q.push(a)}\nfunction T(a,b,c,e){var d=typeof a;if(\"undefined\"===d||\"boolean\"===d)a=null;var g=!1;if(null===a)g=!0;else switch(d){case \"string\":case \"number\":g=!0;break;case \"object\":switch(a.$$typeof){case p:case q:g=!0}}if(g)return c(e,a,\"\"===b?\".\"+U(a,0):b),1;g=0;b=\"\"===b?\".\":b+\":\";if(Array.isArray(a))for(var k=0;k result for the\n // current iteration.\n result.value = unwrapped;\n resolve(result);\n }, function(error) {\n // If a rejected Promise was yielded, throw the rejection back\n // into the async generator function so it can be handled there.\n return invoke(\"throw\", error, resolve, reject);\n });\n }\n }\n\n var previousPromise;\n\n function enqueue(method, arg) {\n function callInvokeWithMethodAndArg() {\n return new PromiseImpl(function(resolve, reject) {\n invoke(method, arg, resolve, reject);\n });\n }\n\n return previousPromise =\n // If enqueue has been called before, then we want to wait until\n // all previous Promises have been resolved before calling invoke,\n // so that results are always delivered in the correct order. If\n // enqueue has not been called before, then it is important to\n // call invoke immediately, without waiting on a callback to fire,\n // so that the async generator function has the opportunity to do\n // any necessary setup in a predictable way. This predictability\n // is why the Promise constructor synchronously invokes its\n // executor callback, and why async functions synchronously\n // execute code before the first await. Since we implement simple\n // async functions in terms of async generators, it is especially\n // important to get this right, even though it requires care.\n previousPromise ? previousPromise.then(\n callInvokeWithMethodAndArg,\n // Avoid propagating failures to Promises returned by later\n // invocations of the iterator.\n callInvokeWithMethodAndArg\n ) : callInvokeWithMethodAndArg();\n }\n\n // Define the unified helper method that is used to implement .next,\n // .throw, and .return (see defineIteratorMethods).\n defineProperty(this, \"_invoke\", { value: enqueue });\n }\n\n defineIteratorMethods(AsyncIterator.prototype);\n define(AsyncIterator.prototype, asyncIteratorSymbol, function () {\n return this;\n });\n exports.AsyncIterator = AsyncIterator;\n\n // Note that simple async functions are implemented on top of\n // AsyncIterator objects; they just return a Promise for the value of\n // the final result produced by the iterator.\n exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) {\n if (PromiseImpl === void 0) PromiseImpl = Promise;\n\n var iter = new AsyncIterator(\n wrap(innerFn, outerFn, self, tryLocsList),\n PromiseImpl\n );\n\n return exports.isGeneratorFunction(outerFn)\n ? iter // If outerFn is a generator, return the full iterator.\n : iter.next().then(function(result) {\n return result.done ? result.value : iter.next();\n });\n };\n\n function makeInvokeMethod(innerFn, self, context) {\n var state = GenStateSuspendedStart;\n\n return function invoke(method, arg) {\n if (state === GenStateExecuting) {\n throw new Error(\"Generator is already running\");\n }\n\n if (state === GenStateCompleted) {\n if (method === \"throw\") {\n throw arg;\n }\n\n // Be forgiving, per 25.3.3.3.3 of the spec:\n // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume\n return doneResult();\n }\n\n context.method = method;\n context.arg = arg;\n\n while (true) {\n var delegate = context.delegate;\n if (delegate) {\n var delegateResult = maybeInvokeDelegate(delegate, context);\n if (delegateResult) {\n if (delegateResult === ContinueSentinel) continue;\n return delegateResult;\n }\n }\n\n if (context.method === \"next\") {\n // Setting context._sent for legacy support of Babel's\n // function.sent implementation.\n context.sent = context._sent = context.arg;\n\n } else if (context.method === \"throw\") {\n if (state === GenStateSuspendedStart) {\n state = GenStateCompleted;\n throw context.arg;\n }\n\n context.dispatchException(context.arg);\n\n } else if (context.method === \"return\") {\n context.abrupt(\"return\", context.arg);\n }\n\n state = GenStateExecuting;\n\n var record = tryCatch(innerFn, self, context);\n if (record.type === \"normal\") {\n // If an exception is thrown from innerFn, we leave state ===\n // GenStateExecuting and loop back for another invocation.\n state = context.done\n ? GenStateCompleted\n : GenStateSuspendedYield;\n\n if (record.arg === ContinueSentinel) {\n continue;\n }\n\n return {\n value: record.arg,\n done: context.done\n };\n\n } else if (record.type === \"throw\") {\n state = GenStateCompleted;\n // Dispatch the exception by looping back around to the\n // context.dispatchException(context.arg) call above.\n context.method = \"throw\";\n context.arg = record.arg;\n }\n }\n };\n }\n\n // Call delegate.iterator[context.method](context.arg) and handle the\n // result, either by returning a { value, done } result from the\n // delegate iterator, or by modifying context.method and context.arg,\n // setting context.delegate to null, and returning the ContinueSentinel.\n function maybeInvokeDelegate(delegate, context) {\n var methodName = context.method;\n var method = delegate.iterator[methodName];\n if (method === undefined) {\n // A .throw or .return when the delegate iterator has no .throw\n // method, or a missing .next mehtod, always terminate the\n // yield* loop.\n context.delegate = null;\n\n // Note: [\"return\"] must be used for ES3 parsing compatibility.\n if (methodName === \"throw\" && delegate.iterator[\"return\"]) {\n // If the delegate iterator has a return method, give it a\n // chance to clean up.\n context.method = \"return\";\n context.arg = undefined;\n maybeInvokeDelegate(delegate, context);\n\n if (context.method === \"throw\") {\n // If maybeInvokeDelegate(context) changed context.method from\n // \"return\" to \"throw\", let that override the TypeError below.\n return ContinueSentinel;\n }\n }\n if (methodName !== \"return\") {\n context.method = \"throw\";\n context.arg = new TypeError(\n \"The iterator does not provide a '\" + methodName + \"' method\");\n }\n\n return ContinueSentinel;\n }\n\n var record = tryCatch(method, delegate.iterator, context.arg);\n\n if (record.type === \"throw\") {\n context.method = \"throw\";\n context.arg = record.arg;\n context.delegate = null;\n return ContinueSentinel;\n }\n\n var info = record.arg;\n\n if (! info) {\n context.method = \"throw\";\n context.arg = new TypeError(\"iterator result is not an object\");\n context.delegate = null;\n return ContinueSentinel;\n }\n\n if (info.done) {\n // Assign the result of the finished delegate to the temporary\n // variable specified by delegate.resultName (see delegateYield).\n context[delegate.resultName] = info.value;\n\n // Resume execution at the desired location (see delegateYield).\n context.next = delegate.nextLoc;\n\n // If context.method was \"throw\" but the delegate handled the\n // exception, let the outer generator proceed normally. If\n // context.method was \"next\", forget context.arg since it has been\n // \"consumed\" by the delegate iterator. If context.method was\n // \"return\", allow the original .return call to continue in the\n // outer generator.\n if (context.method !== \"return\") {\n context.method = \"next\";\n context.arg = undefined;\n }\n\n } else {\n // Re-yield the result returned by the delegate method.\n return info;\n }\n\n // The delegate iterator is finished, so forget it and continue with\n // the outer generator.\n context.delegate = null;\n return ContinueSentinel;\n }\n\n // Define Generator.prototype.{next,throw,return} in terms of the\n // unified ._invoke helper method.\n defineIteratorMethods(Gp);\n\n define(Gp, toStringTagSymbol, \"Generator\");\n\n // A Generator should always return itself as the iterator object when the\n // @@iterator function is called on it. Some browsers' implementations of the\n // iterator prototype chain incorrectly implement this, causing the Generator\n // object to not be returned from this call. This ensures that doesn't happen.\n // See https://github.com/facebook/regenerator/issues/274 for more details.\n define(Gp, iteratorSymbol, function() {\n return this;\n });\n\n define(Gp, \"toString\", function() {\n return \"[object Generator]\";\n });\n\n function pushTryEntry(locs) {\n var entry = { tryLoc: locs[0] };\n\n if (1 in locs) {\n entry.catchLoc = locs[1];\n }\n\n if (2 in locs) {\n entry.finallyLoc = locs[2];\n entry.afterLoc = locs[3];\n }\n\n this.tryEntries.push(entry);\n }\n\n function resetTryEntry(entry) {\n var record = entry.completion || {};\n record.type = \"normal\";\n delete record.arg;\n entry.completion = record;\n }\n\n function Context(tryLocsList) {\n // The root entry object (effectively a try statement without a catch\n // or a finally block) gives us a place to store values thrown from\n // locations where there is no enclosing try statement.\n this.tryEntries = [{ tryLoc: \"root\" }];\n tryLocsList.forEach(pushTryEntry, this);\n this.reset(true);\n }\n\n exports.keys = function(val) {\n var object = Object(val);\n var keys = [];\n for (var key in object) {\n keys.push(key);\n }\n keys.reverse();\n\n // Rather than returning an object with a next method, we keep\n // things simple and return the next function itself.\n return function next() {\n while (keys.length) {\n var key = keys.pop();\n if (key in object) {\n next.value = key;\n next.done = false;\n return next;\n }\n }\n\n // To avoid creating an additional object, we just hang the .value\n // and .done properties off the next function object itself. This\n // also ensures that the minifier will not anonymize the function.\n next.done = true;\n return next;\n };\n };\n\n function values(iterable) {\n if (iterable) {\n var iteratorMethod = iterable[iteratorSymbol];\n if (iteratorMethod) {\n return iteratorMethod.call(iterable);\n }\n\n if (typeof iterable.next === \"function\") {\n return iterable;\n }\n\n if (!isNaN(iterable.length)) {\n var i = -1, next = function next() {\n while (++i < iterable.length) {\n if (hasOwn.call(iterable, i)) {\n next.value = iterable[i];\n next.done = false;\n return next;\n }\n }\n\n next.value = undefined;\n next.done = true;\n\n return next;\n };\n\n return next.next = next;\n }\n }\n\n // Return an iterator with no values.\n return { next: doneResult };\n }\n exports.values = values;\n\n function doneResult() {\n return { value: undefined, done: true };\n }\n\n Context.prototype = {\n constructor: Context,\n\n reset: function(skipTempReset) {\n this.prev = 0;\n this.next = 0;\n // Resetting context._sent for legacy support of Babel's\n // function.sent implementation.\n this.sent = this._sent = undefined;\n this.done = false;\n this.delegate = null;\n\n this.method = \"next\";\n this.arg = undefined;\n\n this.tryEntries.forEach(resetTryEntry);\n\n if (!skipTempReset) {\n for (var name in this) {\n // Not sure about the optimal order of these conditions:\n if (name.charAt(0) === \"t\" &&\n hasOwn.call(this, name) &&\n !isNaN(+name.slice(1))) {\n this[name] = undefined;\n }\n }\n }\n },\n\n stop: function() {\n this.done = true;\n\n var rootEntry = this.tryEntries[0];\n var rootRecord = rootEntry.completion;\n if (rootRecord.type === \"throw\") {\n throw rootRecord.arg;\n }\n\n return this.rval;\n },\n\n dispatchException: function(exception) {\n if (this.done) {\n throw exception;\n }\n\n var context = this;\n function handle(loc, caught) {\n record.type = \"throw\";\n record.arg = exception;\n context.next = loc;\n\n if (caught) {\n // If the dispatched exception was caught by a catch block,\n // then let that catch block handle the exception normally.\n context.method = \"next\";\n context.arg = undefined;\n }\n\n return !! caught;\n }\n\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n var record = entry.completion;\n\n if (entry.tryLoc === \"root\") {\n // Exception thrown outside of any try block that could handle\n // it, so set the completion value of the entire function to\n // throw the exception.\n return handle(\"end\");\n }\n\n if (entry.tryLoc <= this.prev) {\n var hasCatch = hasOwn.call(entry, \"catchLoc\");\n var hasFinally = hasOwn.call(entry, \"finallyLoc\");\n\n if (hasCatch && hasFinally) {\n if (this.prev < entry.catchLoc) {\n return handle(entry.catchLoc, true);\n } else if (this.prev < entry.finallyLoc) {\n return handle(entry.finallyLoc);\n }\n\n } else if (hasCatch) {\n if (this.prev < entry.catchLoc) {\n return handle(entry.catchLoc, true);\n }\n\n } else if (hasFinally) {\n if (this.prev < entry.finallyLoc) {\n return handle(entry.finallyLoc);\n }\n\n } else {\n throw new Error(\"try statement without catch or finally\");\n }\n }\n }\n },\n\n abrupt: function(type, arg) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.tryLoc <= this.prev &&\n hasOwn.call(entry, \"finallyLoc\") &&\n this.prev < entry.finallyLoc) {\n var finallyEntry = entry;\n break;\n }\n }\n\n if (finallyEntry &&\n (type === \"break\" ||\n type === \"continue\") &&\n finallyEntry.tryLoc <= arg &&\n arg <= finallyEntry.finallyLoc) {\n // Ignore the finally entry if control is not jumping to a\n // location outside the try/catch block.\n finallyEntry = null;\n }\n\n var record = finallyEntry ? finallyEntry.completion : {};\n record.type = type;\n record.arg = arg;\n\n if (finallyEntry) {\n this.method = \"next\";\n this.next = finallyEntry.finallyLoc;\n return ContinueSentinel;\n }\n\n return this.complete(record);\n },\n\n complete: function(record, afterLoc) {\n if (record.type === \"throw\") {\n throw record.arg;\n }\n\n if (record.type === \"break\" ||\n record.type === \"continue\") {\n this.next = record.arg;\n } else if (record.type === \"return\") {\n this.rval = this.arg = record.arg;\n this.method = \"return\";\n this.next = \"end\";\n } else if (record.type === \"normal\" && afterLoc) {\n this.next = afterLoc;\n }\n\n return ContinueSentinel;\n },\n\n finish: function(finallyLoc) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.finallyLoc === finallyLoc) {\n this.complete(entry.completion, entry.afterLoc);\n resetTryEntry(entry);\n return ContinueSentinel;\n }\n }\n },\n\n \"catch\": function(tryLoc) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.tryLoc === tryLoc) {\n var record = entry.completion;\n if (record.type === \"throw\") {\n var thrown = record.arg;\n resetTryEntry(entry);\n }\n return thrown;\n }\n }\n\n // The context.catch method must only be called with a location\n // argument that corresponds to a known catch block.\n throw new Error(\"illegal catch attempt\");\n },\n\n delegateYield: function(iterable, resultName, nextLoc) {\n this.delegate = {\n iterator: values(iterable),\n resultName: resultName,\n nextLoc: nextLoc\n };\n\n if (this.method === \"next\") {\n // Deliberately forget the last sent value so that we don't\n // accidentally pass it on to the delegate.\n this.arg = undefined;\n }\n\n return ContinueSentinel;\n }\n };\n\n // Regardless of whether this script is executing as a CommonJS module\n // or not, return the runtime object so that we can declare the variable\n // regeneratorRuntime in the outer scope, which allows this module to be\n // injected easily by `bin/regenerator --include-runtime script.js`.\n return exports;\n\n}(\n // If this script is executing as a CommonJS module, use module.exports\n // as the regeneratorRuntime namespace. Otherwise create a new empty\n // object. Either way, the resulting object will be used to initialize\n // the regeneratorRuntime variable at the top of this file.\n typeof module === \"object\" ? module.exports : {}\n));\n\ntry {\n regeneratorRuntime = runtime;\n} catch (accidentalStrictMode) {\n // This module should not be running in strict mode, so the above\n // assignment should always work unless something is misconfigured. Just\n // in case runtime.js accidentally runs in strict mode, in modern engines\n // we can explicitly access globalThis. In older engines we can escape\n // strict mode using a global Function call. This could conceivably fail\n // if a Content Security Policy forbids using Function, but in that case\n // the proper solution is to fix the accidental strict mode problem. If\n // you've misconfigured your bundler to force strict mode and applied a\n // CSP to forbid Function, and you're not willing to fix either of those\n // problems, please detail your unique predicament in a GitHub issue.\n if (typeof globalThis === \"object\") {\n globalThis.regeneratorRuntime = runtime;\n } else {\n Function(\"r\", \"regeneratorRuntime = r\")(runtime);\n }\n}\n","/** @license React v0.19.1\n * scheduler.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';var f,g,h,k,l;\nif(\"undefined\"===typeof window||\"function\"!==typeof MessageChannel){var p=null,q=null,t=function(){if(null!==p)try{var a=exports.unstable_now();p(!0,a);p=null}catch(b){throw setTimeout(t,0),b;}},u=Date.now();exports.unstable_now=function(){return Date.now()-u};f=function(a){null!==p?setTimeout(f,0,a):(p=a,setTimeout(t,0))};g=function(a,b){q=setTimeout(a,b)};h=function(){clearTimeout(q)};k=function(){return!1};l=exports.unstable_forceFrameRate=function(){}}else{var w=window.performance,x=window.Date,\ny=window.setTimeout,z=window.clearTimeout;if(\"undefined\"!==typeof console){var A=window.cancelAnimationFrame;\"function\"!==typeof window.requestAnimationFrame&&console.error(\"This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\");\"function\"!==typeof A&&console.error(\"This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\")}if(\"object\"===\ntypeof w&&\"function\"===typeof w.now)exports.unstable_now=function(){return w.now()};else{var B=x.now();exports.unstable_now=function(){return x.now()-B}}var C=!1,D=null,E=-1,F=5,G=0;k=function(){return exports.unstable_now()>=G};l=function(){};exports.unstable_forceFrameRate=function(a){0>a||125>>1,e=a[d];if(void 0!==e&&0K(n,c))void 0!==r&&0>K(r,n)?(a[d]=r,a[v]=c,d=v):(a[d]=n,a[m]=c,d=m);else if(void 0!==r&&0>K(r,c))a[d]=r,a[v]=c,d=v;else break a}}return b}return null}function K(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}var N=[],O=[],P=1,Q=null,R=3,S=!1,T=!1,U=!1;\nfunction V(a){for(var b=L(O);null!==b;){if(null===b.callback)M(O);else if(b.startTime<=a)M(O),b.sortIndex=b.expirationTime,J(N,b);else break;b=L(O)}}function W(a){U=!1;V(a);if(!T)if(null!==L(N))T=!0,f(X);else{var b=L(O);null!==b&&g(W,b.startTime-a)}}\nfunction X(a,b){T=!1;U&&(U=!1,h());S=!0;var c=R;try{V(b);for(Q=L(N);null!==Q&&(!(Q.expirationTime>b)||a&&!k());){var d=Q.callback;if(null!==d){Q.callback=null;R=Q.priorityLevel;var e=d(Q.expirationTime<=b);b=exports.unstable_now();\"function\"===typeof e?Q.callback=e:Q===L(N)&&M(N);V(b)}else M(N);Q=L(N)}if(null!==Q)var m=!0;else{var n=L(O);null!==n&&g(W,n.startTime-b);m=!1}return m}finally{Q=null,R=c,S=!1}}\nfunction Y(a){switch(a){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1E4;default:return 5E3}}var Z=l;exports.unstable_IdlePriority=5;exports.unstable_ImmediatePriority=1;exports.unstable_LowPriority=4;exports.unstable_NormalPriority=3;exports.unstable_Profiling=null;exports.unstable_UserBlockingPriority=2;exports.unstable_cancelCallback=function(a){a.callback=null};exports.unstable_continueExecution=function(){T||S||(T=!0,f(X))};\nexports.unstable_getCurrentPriorityLevel=function(){return R};exports.unstable_getFirstCallbackNode=function(){return L(N)};exports.unstable_next=function(a){switch(R){case 1:case 2:case 3:var b=3;break;default:b=R}var c=R;R=b;try{return a()}finally{R=c}};exports.unstable_pauseExecution=function(){};exports.unstable_requestPaint=Z;exports.unstable_runWithPriority=function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3}var c=R;R=a;try{return b()}finally{R=c}};\nexports.unstable_scheduleCallback=function(a,b,c){var d=exports.unstable_now();if(\"object\"===typeof c&&null!==c){var e=c.delay;e=\"number\"===typeof e&&0d?(a.sortIndex=e,J(O,a),null===L(N)&&a===L(O)&&(U?h():U=!0,g(W,e-d))):(a.sortIndex=c,J(N,a),T||S||(T=!0,f(X)));return a};\nexports.unstable_shouldYield=function(){var a=exports.unstable_now();V(a);var b=L(N);return b!==Q&&null!==Q&&null!==b&&null!==b.callback&&b.startTime<=a&&b.expirationTime -1\n }\n}\n\nfunction normalizeName(name) {\n if (typeof name !== 'string') {\n name = String(name)\n }\n if (/[^a-z0-9\\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {\n throw new TypeError('Invalid character in header field name: \"' + name + '\"')\n }\n return name.toLowerCase()\n}\n\nfunction normalizeValue(value) {\n if (typeof value !== 'string') {\n value = String(value)\n }\n return value\n}\n\n// Build a destructive iterator for the value list\nfunction iteratorFor(items) {\n var iterator = {\n next: function() {\n var value = items.shift()\n return {done: value === undefined, value: value}\n }\n }\n\n if (support.iterable) {\n iterator[Symbol.iterator] = function() {\n return iterator\n }\n }\n\n return iterator\n}\n\nexport function Headers(headers) {\n this.map = {}\n\n if (headers instanceof Headers) {\n headers.forEach(function(value, name) {\n this.append(name, value)\n }, this)\n } else if (Array.isArray(headers)) {\n headers.forEach(function(header) {\n this.append(header[0], header[1])\n }, this)\n } else if (headers) {\n Object.getOwnPropertyNames(headers).forEach(function(name) {\n this.append(name, headers[name])\n }, this)\n }\n}\n\nHeaders.prototype.append = function(name, value) {\n name = normalizeName(name)\n value = normalizeValue(value)\n var oldValue = this.map[name]\n this.map[name] = oldValue ? oldValue + ', ' + value : value\n}\n\nHeaders.prototype['delete'] = function(name) {\n delete this.map[normalizeName(name)]\n}\n\nHeaders.prototype.get = function(name) {\n name = normalizeName(name)\n return this.has(name) ? this.map[name] : null\n}\n\nHeaders.prototype.has = function(name) {\n return this.map.hasOwnProperty(normalizeName(name))\n}\n\nHeaders.prototype.set = function(name, value) {\n this.map[normalizeName(name)] = normalizeValue(value)\n}\n\nHeaders.prototype.forEach = function(callback, thisArg) {\n for (var name in this.map) {\n if (this.map.hasOwnProperty(name)) {\n callback.call(thisArg, this.map[name], name, this)\n }\n }\n}\n\nHeaders.prototype.keys = function() {\n var items = []\n this.forEach(function(value, name) {\n items.push(name)\n })\n return iteratorFor(items)\n}\n\nHeaders.prototype.values = function() {\n var items = []\n this.forEach(function(value) {\n items.push(value)\n })\n return iteratorFor(items)\n}\n\nHeaders.prototype.entries = function() {\n var items = []\n this.forEach(function(value, name) {\n items.push([name, value])\n })\n return iteratorFor(items)\n}\n\nif (support.iterable) {\n Headers.prototype[Symbol.iterator] = Headers.prototype.entries\n}\n\nfunction consumed(body) {\n if (body.bodyUsed) {\n return Promise.reject(new TypeError('Already read'))\n }\n body.bodyUsed = true\n}\n\nfunction fileReaderReady(reader) {\n return new Promise(function(resolve, reject) {\n reader.onload = function() {\n resolve(reader.result)\n }\n reader.onerror = function() {\n reject(reader.error)\n }\n })\n}\n\nfunction readBlobAsArrayBuffer(blob) {\n var reader = new FileReader()\n var promise = fileReaderReady(reader)\n reader.readAsArrayBuffer(blob)\n return promise\n}\n\nfunction readBlobAsText(blob) {\n var reader = new FileReader()\n var promise = fileReaderReady(reader)\n reader.readAsText(blob)\n return promise\n}\n\nfunction readArrayBufferAsText(buf) {\n var view = new Uint8Array(buf)\n var chars = new Array(view.length)\n\n for (var i = 0; i < view.length; i++) {\n chars[i] = String.fromCharCode(view[i])\n }\n return chars.join('')\n}\n\nfunction bufferClone(buf) {\n if (buf.slice) {\n return buf.slice(0)\n } else {\n var view = new Uint8Array(buf.byteLength)\n view.set(new Uint8Array(buf))\n return view.buffer\n }\n}\n\nfunction Body() {\n this.bodyUsed = false\n\n this._initBody = function(body) {\n /*\n fetch-mock wraps the Response object in an ES6 Proxy to\n provide useful test harness features such as flush. However, on\n ES5 browsers without fetch or Proxy support pollyfills must be used;\n the proxy-pollyfill is unable to proxy an attribute unless it exists\n on the object before the Proxy is created. This change ensures\n Response.bodyUsed exists on the instance, while maintaining the\n semantic of setting Request.bodyUsed in the constructor before\n _initBody is called.\n */\n this.bodyUsed = this.bodyUsed\n this._bodyInit = body\n if (!body) {\n this._bodyText = ''\n } else if (typeof body === 'string') {\n this._bodyText = body\n } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {\n this._bodyBlob = body\n } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {\n this._bodyFormData = body\n } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n this._bodyText = body.toString()\n } else if (support.arrayBuffer && support.blob && isDataView(body)) {\n this._bodyArrayBuffer = bufferClone(body.buffer)\n // IE 10-11 can't handle a DataView body.\n this._bodyInit = new Blob([this._bodyArrayBuffer])\n } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {\n this._bodyArrayBuffer = bufferClone(body)\n } else {\n this._bodyText = body = Object.prototype.toString.call(body)\n }\n\n if (!this.headers.get('content-type')) {\n if (typeof body === 'string') {\n this.headers.set('content-type', 'text/plain;charset=UTF-8')\n } else if (this._bodyBlob && this._bodyBlob.type) {\n this.headers.set('content-type', this._bodyBlob.type)\n } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')\n }\n }\n }\n\n if (support.blob) {\n this.blob = function() {\n var rejected = consumed(this)\n if (rejected) {\n return rejected\n }\n\n if (this._bodyBlob) {\n return Promise.resolve(this._bodyBlob)\n } else if (this._bodyArrayBuffer) {\n return Promise.resolve(new Blob([this._bodyArrayBuffer]))\n } else if (this._bodyFormData) {\n throw new Error('could not read FormData body as blob')\n } else {\n return Promise.resolve(new Blob([this._bodyText]))\n }\n }\n\n this.arrayBuffer = function() {\n if (this._bodyArrayBuffer) {\n var isConsumed = consumed(this)\n if (isConsumed) {\n return isConsumed\n }\n if (ArrayBuffer.isView(this._bodyArrayBuffer)) {\n return Promise.resolve(\n this._bodyArrayBuffer.buffer.slice(\n this._bodyArrayBuffer.byteOffset,\n this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength\n )\n )\n } else {\n return Promise.resolve(this._bodyArrayBuffer)\n }\n } else {\n return this.blob().then(readBlobAsArrayBuffer)\n }\n }\n }\n\n this.text = function() {\n var rejected = consumed(this)\n if (rejected) {\n return rejected\n }\n\n if (this._bodyBlob) {\n return readBlobAsText(this._bodyBlob)\n } else if (this._bodyArrayBuffer) {\n return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))\n } else if (this._bodyFormData) {\n throw new Error('could not read FormData body as text')\n } else {\n return Promise.resolve(this._bodyText)\n }\n }\n\n if (support.formData) {\n this.formData = function() {\n return this.text().then(decode)\n }\n }\n\n this.json = function() {\n return this.text().then(JSON.parse)\n }\n\n return this\n}\n\n// HTTP methods whose capitalization should be normalized\nvar methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']\n\nfunction normalizeMethod(method) {\n var upcased = method.toUpperCase()\n return methods.indexOf(upcased) > -1 ? upcased : method\n}\n\nexport function Request(input, options) {\n if (!(this instanceof Request)) {\n throw new TypeError('Please use the \"new\" operator, this DOM object constructor cannot be called as a function.')\n }\n\n options = options || {}\n var body = options.body\n\n if (input instanceof Request) {\n if (input.bodyUsed) {\n throw new TypeError('Already read')\n }\n this.url = input.url\n this.credentials = input.credentials\n if (!options.headers) {\n this.headers = new Headers(input.headers)\n }\n this.method = input.method\n this.mode = input.mode\n this.signal = input.signal\n if (!body && input._bodyInit != null) {\n body = input._bodyInit\n input.bodyUsed = true\n }\n } else {\n this.url = String(input)\n }\n\n this.credentials = options.credentials || this.credentials || 'same-origin'\n if (options.headers || !this.headers) {\n this.headers = new Headers(options.headers)\n }\n this.method = normalizeMethod(options.method || this.method || 'GET')\n this.mode = options.mode || this.mode || null\n this.signal = options.signal || this.signal\n this.referrer = null\n\n if ((this.method === 'GET' || this.method === 'HEAD') && body) {\n throw new TypeError('Body not allowed for GET or HEAD requests')\n }\n this._initBody(body)\n\n if (this.method === 'GET' || this.method === 'HEAD') {\n if (options.cache === 'no-store' || options.cache === 'no-cache') {\n // Search for a '_' parameter in the query string\n var reParamSearch = /([?&])_=[^&]*/\n if (reParamSearch.test(this.url)) {\n // If it already exists then set the value with the current time\n this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime())\n } else {\n // Otherwise add a new '_' parameter to the end with the current time\n var reQueryString = /\\?/\n this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime()\n }\n }\n }\n}\n\nRequest.prototype.clone = function() {\n return new Request(this, {body: this._bodyInit})\n}\n\nfunction decode(body) {\n var form = new FormData()\n body\n .trim()\n .split('&')\n .forEach(function(bytes) {\n if (bytes) {\n var split = bytes.split('=')\n var name = split.shift().replace(/\\+/g, ' ')\n var value = split.join('=').replace(/\\+/g, ' ')\n form.append(decodeURIComponent(name), decodeURIComponent(value))\n }\n })\n return form\n}\n\nfunction parseHeaders(rawHeaders) {\n var headers = new Headers()\n // Replace instances of \\r\\n and \\n followed by at least one space or horizontal tab with a space\n // https://tools.ietf.org/html/rfc7230#section-3.2\n var preProcessedHeaders = rawHeaders.replace(/\\r?\\n[\\t ]+/g, ' ')\n // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill\n // https://github.com/github/fetch/issues/748\n // https://github.com/zloirock/core-js/issues/751\n preProcessedHeaders\n .split('\\r')\n .map(function(header) {\n return header.indexOf('\\n') === 0 ? header.substr(1, header.length) : header\n })\n .forEach(function(line) {\n var parts = line.split(':')\n var key = parts.shift().trim()\n if (key) {\n var value = parts.join(':').trim()\n headers.append(key, value)\n }\n })\n return headers\n}\n\nBody.call(Request.prototype)\n\nexport function Response(bodyInit, options) {\n if (!(this instanceof Response)) {\n throw new TypeError('Please use the \"new\" operator, this DOM object constructor cannot be called as a function.')\n }\n if (!options) {\n options = {}\n }\n\n this.type = 'default'\n this.status = options.status === undefined ? 200 : options.status\n this.ok = this.status >= 200 && this.status < 300\n this.statusText = options.statusText === undefined ? '' : '' + options.statusText\n this.headers = new Headers(options.headers)\n this.url = options.url || ''\n this._initBody(bodyInit)\n}\n\nBody.call(Response.prototype)\n\nResponse.prototype.clone = function() {\n return new Response(this._bodyInit, {\n status: this.status,\n statusText: this.statusText,\n headers: new Headers(this.headers),\n url: this.url\n })\n}\n\nResponse.error = function() {\n var response = new Response(null, {status: 0, statusText: ''})\n response.type = 'error'\n return response\n}\n\nvar redirectStatuses = [301, 302, 303, 307, 308]\n\nResponse.redirect = function(url, status) {\n if (redirectStatuses.indexOf(status) === -1) {\n throw new RangeError('Invalid status code')\n }\n\n return new Response(null, {status: status, headers: {location: url}})\n}\n\nexport var DOMException = global.DOMException\ntry {\n new DOMException()\n} catch (err) {\n DOMException = function(message, name) {\n this.message = message\n this.name = name\n var error = Error(message)\n this.stack = error.stack\n }\n DOMException.prototype = Object.create(Error.prototype)\n DOMException.prototype.constructor = DOMException\n}\n\nexport function fetch(input, init) {\n return new Promise(function(resolve, reject) {\n var request = new Request(input, init)\n\n if (request.signal && request.signal.aborted) {\n return reject(new DOMException('Aborted', 'AbortError'))\n }\n\n var xhr = new XMLHttpRequest()\n\n function abortXhr() {\n xhr.abort()\n }\n\n xhr.onload = function() {\n var options = {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseHeaders(xhr.getAllResponseHeaders() || '')\n }\n options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')\n var body = 'response' in xhr ? xhr.response : xhr.responseText\n setTimeout(function() {\n resolve(new Response(body, options))\n }, 0)\n }\n\n xhr.onerror = function() {\n setTimeout(function() {\n reject(new TypeError('Network request failed'))\n }, 0)\n }\n\n xhr.ontimeout = function() {\n setTimeout(function() {\n reject(new TypeError('Network request failed'))\n }, 0)\n }\n\n xhr.onabort = function() {\n setTimeout(function() {\n reject(new DOMException('Aborted', 'AbortError'))\n }, 0)\n }\n\n function fixUrl(url) {\n try {\n return url === '' && global.location.href ? global.location.href : url\n } catch (e) {\n return url\n }\n }\n\n xhr.open(request.method, fixUrl(request.url), true)\n\n if (request.credentials === 'include') {\n xhr.withCredentials = true\n } else if (request.credentials === 'omit') {\n xhr.withCredentials = false\n }\n\n if ('responseType' in xhr) {\n if (support.blob) {\n xhr.responseType = 'blob'\n } else if (\n support.arrayBuffer &&\n request.headers.get('Content-Type') &&\n request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1\n ) {\n xhr.responseType = 'arraybuffer'\n }\n }\n\n if (init && typeof init.headers === 'object' && !(init.headers instanceof Headers)) {\n Object.getOwnPropertyNames(init.headers).forEach(function(name) {\n xhr.setRequestHeader(name, normalizeValue(init.headers[name]))\n })\n } else {\n request.headers.forEach(function(value, name) {\n xhr.setRequestHeader(name, value)\n })\n }\n\n if (request.signal) {\n request.signal.addEventListener('abort', abortXhr)\n\n xhr.onreadystatechange = function() {\n // DONE (success or failure)\n if (xhr.readyState === 4) {\n request.signal.removeEventListener('abort', abortXhr)\n }\n }\n }\n\n xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)\n })\n}\n\nfetch.polyfill = true\n\nif (!global.fetch) {\n global.fetch = fetch\n global.Headers = Headers\n global.Request = Request\n global.Response = Response\n}\n","var _typeof = require(\"./typeof.js\")[\"default\"];\nfunction _regeneratorRuntime() {\n \"use strict\"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */\n module.exports = _regeneratorRuntime = function _regeneratorRuntime() {\n return exports;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;\n var exports = {},\n Op = Object.prototype,\n hasOwn = Op.hasOwnProperty,\n defineProperty = Object.defineProperty || function (obj, key, desc) {\n obj[key] = desc.value;\n },\n $Symbol = \"function\" == typeof Symbol ? Symbol : {},\n iteratorSymbol = $Symbol.iterator || \"@@iterator\",\n asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\",\n toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n function define(obj, key, value) {\n return Object.defineProperty(obj, key, {\n value: value,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }), obj[key];\n }\n try {\n define({}, \"\");\n } catch (err) {\n define = function define(obj, key, value) {\n return obj[key] = value;\n };\n }\n function wrap(innerFn, outerFn, self, tryLocsList) {\n var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,\n generator = Object.create(protoGenerator.prototype),\n context = new Context(tryLocsList || []);\n return defineProperty(generator, \"_invoke\", {\n value: makeInvokeMethod(innerFn, self, context)\n }), generator;\n }\n function tryCatch(fn, obj, arg) {\n try {\n return {\n type: \"normal\",\n arg: fn.call(obj, arg)\n };\n } catch (err) {\n return {\n type: \"throw\",\n arg: err\n };\n }\n }\n exports.wrap = wrap;\n var ContinueSentinel = {};\n function Generator() {}\n function GeneratorFunction() {}\n function GeneratorFunctionPrototype() {}\n var IteratorPrototype = {};\n define(IteratorPrototype, iteratorSymbol, function () {\n return this;\n });\n var getProto = Object.getPrototypeOf,\n NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);\n var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);\n function defineIteratorMethods(prototype) {\n [\"next\", \"throw\", \"return\"].forEach(function (method) {\n define(prototype, method, function (arg) {\n return this._invoke(method, arg);\n });\n });\n }\n function AsyncIterator(generator, PromiseImpl) {\n function invoke(method, arg, resolve, reject) {\n var record = tryCatch(generator[method], generator, arg);\n if (\"throw\" !== record.type) {\n var result = record.arg,\n value = result.value;\n return value && \"object\" == _typeof(value) && hasOwn.call(value, \"__await\") ? PromiseImpl.resolve(value.__await).then(function (value) {\n invoke(\"next\", value, resolve, reject);\n }, function (err) {\n invoke(\"throw\", err, resolve, reject);\n }) : PromiseImpl.resolve(value).then(function (unwrapped) {\n result.value = unwrapped, resolve(result);\n }, function (error) {\n return invoke(\"throw\", error, resolve, reject);\n });\n }\n reject(record.arg);\n }\n var previousPromise;\n defineProperty(this, \"_invoke\", {\n value: function value(method, arg) {\n function callInvokeWithMethodAndArg() {\n return new PromiseImpl(function (resolve, reject) {\n invoke(method, arg, resolve, reject);\n });\n }\n return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();\n }\n });\n }\n function makeInvokeMethod(innerFn, self, context) {\n var state = \"suspendedStart\";\n return function (method, arg) {\n if (\"executing\" === state) throw new Error(\"Generator is already running\");\n if (\"completed\" === state) {\n if (\"throw\" === method) throw arg;\n return doneResult();\n }\n for (context.method = method, context.arg = arg;;) {\n var delegate = context.delegate;\n if (delegate) {\n var delegateResult = maybeInvokeDelegate(delegate, context);\n if (delegateResult) {\n if (delegateResult === ContinueSentinel) continue;\n return delegateResult;\n }\n }\n if (\"next\" === context.method) context.sent = context._sent = context.arg;else if (\"throw\" === context.method) {\n if (\"suspendedStart\" === state) throw state = \"completed\", context.arg;\n context.dispatchException(context.arg);\n } else \"return\" === context.method && context.abrupt(\"return\", context.arg);\n state = \"executing\";\n var record = tryCatch(innerFn, self, context);\n if (\"normal\" === record.type) {\n if (state = context.done ? \"completed\" : \"suspendedYield\", record.arg === ContinueSentinel) continue;\n return {\n value: record.arg,\n done: context.done\n };\n }\n \"throw\" === record.type && (state = \"completed\", context.method = \"throw\", context.arg = record.arg);\n }\n };\n }\n function maybeInvokeDelegate(delegate, context) {\n var methodName = context.method,\n method = delegate.iterator[methodName];\n if (undefined === method) return context.delegate = null, \"throw\" === methodName && delegate.iterator[\"return\"] && (context.method = \"return\", context.arg = undefined, maybeInvokeDelegate(delegate, context), \"throw\" === context.method) || \"return\" !== methodName && (context.method = \"throw\", context.arg = new TypeError(\"The iterator does not provide a '\" + methodName + \"' method\")), ContinueSentinel;\n var record = tryCatch(method, delegate.iterator, context.arg);\n if (\"throw\" === record.type) return context.method = \"throw\", context.arg = record.arg, context.delegate = null, ContinueSentinel;\n var info = record.arg;\n return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, \"return\" !== context.method && (context.method = \"next\", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = \"throw\", context.arg = new TypeError(\"iterator result is not an object\"), context.delegate = null, ContinueSentinel);\n }\n function pushTryEntry(locs) {\n var entry = {\n tryLoc: locs[0]\n };\n 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);\n }\n function resetTryEntry(entry) {\n var record = entry.completion || {};\n record.type = \"normal\", delete record.arg, entry.completion = record;\n }\n function Context(tryLocsList) {\n this.tryEntries = [{\n tryLoc: \"root\"\n }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);\n }\n function values(iterable) {\n if (iterable) {\n var iteratorMethod = iterable[iteratorSymbol];\n if (iteratorMethod) return iteratorMethod.call(iterable);\n if (\"function\" == typeof iterable.next) return iterable;\n if (!isNaN(iterable.length)) {\n var i = -1,\n next = function next() {\n for (; ++i < iterable.length;) {\n if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;\n }\n return next.value = undefined, next.done = !0, next;\n };\n return next.next = next;\n }\n }\n return {\n next: doneResult\n };\n }\n function doneResult() {\n return {\n value: undefined,\n done: !0\n };\n }\n return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, \"constructor\", {\n value: GeneratorFunctionPrototype,\n configurable: !0\n }), defineProperty(GeneratorFunctionPrototype, \"constructor\", {\n value: GeneratorFunction,\n configurable: !0\n }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, \"GeneratorFunction\"), exports.isGeneratorFunction = function (genFun) {\n var ctor = \"function\" == typeof genFun && genFun.constructor;\n return !!ctor && (ctor === GeneratorFunction || \"GeneratorFunction\" === (ctor.displayName || ctor.name));\n }, exports.mark = function (genFun) {\n return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, \"GeneratorFunction\")), genFun.prototype = Object.create(Gp), genFun;\n }, exports.awrap = function (arg) {\n return {\n __await: arg\n };\n }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {\n return this;\n }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {\n void 0 === PromiseImpl && (PromiseImpl = Promise);\n var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);\n return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {\n return result.done ? result.value : iter.next();\n });\n }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, \"Generator\"), define(Gp, iteratorSymbol, function () {\n return this;\n }), define(Gp, \"toString\", function () {\n return \"[object Generator]\";\n }), exports.keys = function (val) {\n var object = Object(val),\n keys = [];\n for (var key in object) {\n keys.push(key);\n }\n return keys.reverse(), function next() {\n for (; keys.length;) {\n var key = keys.pop();\n if (key in object) return next.value = key, next.done = !1, next;\n }\n return next.done = !0, next;\n };\n }, exports.values = values, Context.prototype = {\n constructor: Context,\n reset: function reset(skipTempReset) {\n if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = \"next\", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) {\n \"t\" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);\n }\n },\n stop: function stop() {\n this.done = !0;\n var rootRecord = this.tryEntries[0].completion;\n if (\"throw\" === rootRecord.type) throw rootRecord.arg;\n return this.rval;\n },\n dispatchException: function dispatchException(exception) {\n if (this.done) throw exception;\n var context = this;\n function handle(loc, caught) {\n return record.type = \"throw\", record.arg = exception, context.next = loc, caught && (context.method = \"next\", context.arg = undefined), !!caught;\n }\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i],\n record = entry.completion;\n if (\"root\" === entry.tryLoc) return handle(\"end\");\n if (entry.tryLoc <= this.prev) {\n var hasCatch = hasOwn.call(entry, \"catchLoc\"),\n hasFinally = hasOwn.call(entry, \"finallyLoc\");\n if (hasCatch && hasFinally) {\n if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);\n if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);\n } else if (hasCatch) {\n if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);\n } else {\n if (!hasFinally) throw new Error(\"try statement without catch or finally\");\n if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);\n }\n }\n }\n },\n abrupt: function abrupt(type, arg) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.tryLoc <= this.prev && hasOwn.call(entry, \"finallyLoc\") && this.prev < entry.finallyLoc) {\n var finallyEntry = entry;\n break;\n }\n }\n finallyEntry && (\"break\" === type || \"continue\" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);\n var record = finallyEntry ? finallyEntry.completion : {};\n return record.type = type, record.arg = arg, finallyEntry ? (this.method = \"next\", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);\n },\n complete: function complete(record, afterLoc) {\n if (\"throw\" === record.type) throw record.arg;\n return \"break\" === record.type || \"continue\" === record.type ? this.next = record.arg : \"return\" === record.type ? (this.rval = this.arg = record.arg, this.method = \"return\", this.next = \"end\") : \"normal\" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;\n },\n finish: function finish(finallyLoc) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;\n }\n },\n \"catch\": function _catch(tryLoc) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.tryLoc === tryLoc) {\n var record = entry.completion;\n if (\"throw\" === record.type) {\n var thrown = record.arg;\n resetTryEntry(entry);\n }\n return thrown;\n }\n }\n throw new Error(\"illegal catch attempt\");\n },\n delegateYield: function delegateYield(iterable, resultName, nextLoc) {\n return this.delegate = {\n iterator: values(iterable),\n resultName: resultName,\n nextLoc: nextLoc\n }, \"next\" === this.method && (this.arg = undefined), ContinueSentinel;\n }\n }, exports;\n}\nmodule.exports = _regeneratorRuntime, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n return (module.exports = _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) {\n return typeof obj;\n } : function (obj) {\n return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports), _typeof(obj);\n}\nmodule.exports = _typeof, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","// TODO(Babel 8): Remove this file.\n\nvar runtime = require(\"../helpers/regeneratorRuntime\")();\nmodule.exports = runtime;\n\n// Copied from https://github.com/facebook/regenerator/blob/main/packages/runtime/runtime.js#L736=\ntry {\n regeneratorRuntime = runtime;\n} catch (accidentalStrictMode) {\n if (typeof globalThis === \"object\") {\n globalThis.regeneratorRuntime = runtime;\n } else {\n Function(\"r\", \"regeneratorRuntime = r\")(runtime);\n }\n}\n","export default function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n for (var i = 0, arr2 = new Array(len); i < len; i++) {\n arr2[i] = arr[i];\n }\n return arr2;\n}","export default function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n return self;\n}","function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n try {\n var info = gen[key](arg);\n var value = info.value;\n } catch (error) {\n reject(error);\n return;\n }\n if (info.done) {\n resolve(value);\n } else {\n Promise.resolve(value).then(_next, _throw);\n }\n}\nexport default function _asyncToGenerator(fn) {\n return function () {\n var self = this,\n args = arguments;\n return new Promise(function (resolve, reject) {\n var gen = fn.apply(self, args);\n function _next(value) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value);\n }\n function _throw(err) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err);\n }\n _next(undefined);\n });\n };\n}","export default function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}","import toPropertyKey from \"./toPropertyKey.js\";\nfunction _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, toPropertyKey(descriptor.key), descriptor);\n }\n}\nexport default function _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n Object.defineProperty(Constructor, \"prototype\", {\n writable: false\n });\n return Constructor;\n}","import _typeof from \"./typeof.js\";\nimport assertThisInitialized from \"./assertThisInitialized.js\";\nexport default function _possibleConstructorReturn(self, call) {\n if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) {\n return call;\n } else if (call !== void 0) {\n throw new TypeError(\"Derived constructors may only return object or undefined\");\n }\n return assertThisInitialized(self);\n}","import getPrototypeOf from \"./getPrototypeOf.js\";\nimport isNativeReflectConstruct from \"./isNativeReflectConstruct.js\";\nimport possibleConstructorReturn from \"./possibleConstructorReturn.js\";\nexport default function _createSuper(Derived) {\n var hasNativeReflectConstruct = isNativeReflectConstruct();\n return function _createSuperInternal() {\n var Super = getPrototypeOf(Derived),\n result;\n if (hasNativeReflectConstruct) {\n var NewTarget = getPrototypeOf(this).constructor;\n result = Reflect.construct(Super, arguments, NewTarget);\n } else {\n result = Super.apply(this, arguments);\n }\n return possibleConstructorReturn(this, result);\n };\n}","import toPropertyKey from \"./toPropertyKey.js\";\nexport default function _defineProperty(obj, key, value) {\n key = toPropertyKey(key);\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n}","export default function _extends() {\n _extends = Object.assign ? Object.assign.bind() : function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n return target;\n };\n return _extends.apply(this, arguments);\n}","import getPrototypeOf from \"./getPrototypeOf.js\";\nexport default function _superPropBase(object, property) {\n while (!Object.prototype.hasOwnProperty.call(object, property)) {\n object = getPrototypeOf(object);\n if (object === null) break;\n }\n return object;\n}","import superPropBase from \"./superPropBase.js\";\nexport default function _get() {\n if (typeof Reflect !== \"undefined\" && Reflect.get) {\n _get = Reflect.get.bind();\n } else {\n _get = function _get(target, property, receiver) {\n var base = superPropBase(target, property);\n if (!base) return;\n var desc = Object.getOwnPropertyDescriptor(base, property);\n if (desc.get) {\n return desc.get.call(arguments.length < 3 ? target : receiver);\n }\n return desc.value;\n };\n }\n return _get.apply(this, arguments);\n}","export default function _getPrototypeOf(o) {\n _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {\n return o.__proto__ || Object.getPrototypeOf(o);\n };\n return _getPrototypeOf(o);\n}","import setPrototypeOf from \"./setPrototypeOf.js\";\nexport default function _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n writable: true,\n configurable: true\n }\n });\n Object.defineProperty(subClass, \"prototype\", {\n writable: false\n });\n if (superClass) setPrototypeOf(subClass, superClass);\n}","export default function _isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n try {\n Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n return true;\n } catch (e) {\n return false;\n }\n}","import defineProperty from \"./defineProperty.js\";\nfunction ownKeys(object, enumerableOnly) {\n var keys = Object.keys(object);\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(object);\n enumerableOnly && (symbols = symbols.filter(function (sym) {\n return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n })), keys.push.apply(keys, symbols);\n }\n return keys;\n}\nexport default function _objectSpread2(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = null != arguments[i] ? arguments[i] : {};\n i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {\n defineProperty(target, key, source[key]);\n }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {\n Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n });\n }\n return target;\n}","import objectWithoutPropertiesLoose from \"./objectWithoutPropertiesLoose.js\";\nexport default function _objectWithoutProperties(source, excluded) {\n if (source == null) return {};\n var target = objectWithoutPropertiesLoose(source, excluded);\n var key, i;\n if (Object.getOwnPropertySymbols) {\n var sourceSymbolKeys = Object.getOwnPropertySymbols(source);\n for (i = 0; i < sourceSymbolKeys.length; i++) {\n key = sourceSymbolKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n target[key] = source[key];\n }\n }\n return target;\n}","export default function _objectWithoutPropertiesLoose(source, excluded) {\n if (source == null) return {};\n var target = {};\n var sourceKeys = Object.keys(source);\n var key, i;\n for (i = 0; i < sourceKeys.length; i++) {\n key = sourceKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n target[key] = source[key];\n }\n return target;\n}","import _typeof from \"./typeof.js\";\nexport default function _regeneratorRuntime() {\n \"use strict\"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */\n _regeneratorRuntime = function _regeneratorRuntime() {\n return exports;\n };\n var exports = {},\n Op = Object.prototype,\n hasOwn = Op.hasOwnProperty,\n defineProperty = Object.defineProperty || function (obj, key, desc) {\n obj[key] = desc.value;\n },\n $Symbol = \"function\" == typeof Symbol ? Symbol : {},\n iteratorSymbol = $Symbol.iterator || \"@@iterator\",\n asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\",\n toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n function define(obj, key, value) {\n return Object.defineProperty(obj, key, {\n value: value,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }), obj[key];\n }\n try {\n define({}, \"\");\n } catch (err) {\n define = function define(obj, key, value) {\n return obj[key] = value;\n };\n }\n function wrap(innerFn, outerFn, self, tryLocsList) {\n var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,\n generator = Object.create(protoGenerator.prototype),\n context = new Context(tryLocsList || []);\n return defineProperty(generator, \"_invoke\", {\n value: makeInvokeMethod(innerFn, self, context)\n }), generator;\n }\n function tryCatch(fn, obj, arg) {\n try {\n return {\n type: \"normal\",\n arg: fn.call(obj, arg)\n };\n } catch (err) {\n return {\n type: \"throw\",\n arg: err\n };\n }\n }\n exports.wrap = wrap;\n var ContinueSentinel = {};\n function Generator() {}\n function GeneratorFunction() {}\n function GeneratorFunctionPrototype() {}\n var IteratorPrototype = {};\n define(IteratorPrototype, iteratorSymbol, function () {\n return this;\n });\n var getProto = Object.getPrototypeOf,\n NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);\n var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);\n function defineIteratorMethods(prototype) {\n [\"next\", \"throw\", \"return\"].forEach(function (method) {\n define(prototype, method, function (arg) {\n return this._invoke(method, arg);\n });\n });\n }\n function AsyncIterator(generator, PromiseImpl) {\n function invoke(method, arg, resolve, reject) {\n var record = tryCatch(generator[method], generator, arg);\n if (\"throw\" !== record.type) {\n var result = record.arg,\n value = result.value;\n return value && \"object\" == _typeof(value) && hasOwn.call(value, \"__await\") ? PromiseImpl.resolve(value.__await).then(function (value) {\n invoke(\"next\", value, resolve, reject);\n }, function (err) {\n invoke(\"throw\", err, resolve, reject);\n }) : PromiseImpl.resolve(value).then(function (unwrapped) {\n result.value = unwrapped, resolve(result);\n }, function (error) {\n return invoke(\"throw\", error, resolve, reject);\n });\n }\n reject(record.arg);\n }\n var previousPromise;\n defineProperty(this, \"_invoke\", {\n value: function value(method, arg) {\n function callInvokeWithMethodAndArg() {\n return new PromiseImpl(function (resolve, reject) {\n invoke(method, arg, resolve, reject);\n });\n }\n return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();\n }\n });\n }\n function makeInvokeMethod(innerFn, self, context) {\n var state = \"suspendedStart\";\n return function (method, arg) {\n if (\"executing\" === state) throw new Error(\"Generator is already running\");\n if (\"completed\" === state) {\n if (\"throw\" === method) throw arg;\n return doneResult();\n }\n for (context.method = method, context.arg = arg;;) {\n var delegate = context.delegate;\n if (delegate) {\n var delegateResult = maybeInvokeDelegate(delegate, context);\n if (delegateResult) {\n if (delegateResult === ContinueSentinel) continue;\n return delegateResult;\n }\n }\n if (\"next\" === context.method) context.sent = context._sent = context.arg;else if (\"throw\" === context.method) {\n if (\"suspendedStart\" === state) throw state = \"completed\", context.arg;\n context.dispatchException(context.arg);\n } else \"return\" === context.method && context.abrupt(\"return\", context.arg);\n state = \"executing\";\n var record = tryCatch(innerFn, self, context);\n if (\"normal\" === record.type) {\n if (state = context.done ? \"completed\" : \"suspendedYield\", record.arg === ContinueSentinel) continue;\n return {\n value: record.arg,\n done: context.done\n };\n }\n \"throw\" === record.type && (state = \"completed\", context.method = \"throw\", context.arg = record.arg);\n }\n };\n }\n function maybeInvokeDelegate(delegate, context) {\n var methodName = context.method,\n method = delegate.iterator[methodName];\n if (undefined === method) return context.delegate = null, \"throw\" === methodName && delegate.iterator[\"return\"] && (context.method = \"return\", context.arg = undefined, maybeInvokeDelegate(delegate, context), \"throw\" === context.method) || \"return\" !== methodName && (context.method = \"throw\", context.arg = new TypeError(\"The iterator does not provide a '\" + methodName + \"' method\")), ContinueSentinel;\n var record = tryCatch(method, delegate.iterator, context.arg);\n if (\"throw\" === record.type) return context.method = \"throw\", context.arg = record.arg, context.delegate = null, ContinueSentinel;\n var info = record.arg;\n return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, \"return\" !== context.method && (context.method = \"next\", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = \"throw\", context.arg = new TypeError(\"iterator result is not an object\"), context.delegate = null, ContinueSentinel);\n }\n function pushTryEntry(locs) {\n var entry = {\n tryLoc: locs[0]\n };\n 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);\n }\n function resetTryEntry(entry) {\n var record = entry.completion || {};\n record.type = \"normal\", delete record.arg, entry.completion = record;\n }\n function Context(tryLocsList) {\n this.tryEntries = [{\n tryLoc: \"root\"\n }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);\n }\n function values(iterable) {\n if (iterable) {\n var iteratorMethod = iterable[iteratorSymbol];\n if (iteratorMethod) return iteratorMethod.call(iterable);\n if (\"function\" == typeof iterable.next) return iterable;\n if (!isNaN(iterable.length)) {\n var i = -1,\n next = function next() {\n for (; ++i < iterable.length;) {\n if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;\n }\n return next.value = undefined, next.done = !0, next;\n };\n return next.next = next;\n }\n }\n return {\n next: doneResult\n };\n }\n function doneResult() {\n return {\n value: undefined,\n done: !0\n };\n }\n return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, \"constructor\", {\n value: GeneratorFunctionPrototype,\n configurable: !0\n }), defineProperty(GeneratorFunctionPrototype, \"constructor\", {\n value: GeneratorFunction,\n configurable: !0\n }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, \"GeneratorFunction\"), exports.isGeneratorFunction = function (genFun) {\n var ctor = \"function\" == typeof genFun && genFun.constructor;\n return !!ctor && (ctor === GeneratorFunction || \"GeneratorFunction\" === (ctor.displayName || ctor.name));\n }, exports.mark = function (genFun) {\n return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, \"GeneratorFunction\")), genFun.prototype = Object.create(Gp), genFun;\n }, exports.awrap = function (arg) {\n return {\n __await: arg\n };\n }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {\n return this;\n }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {\n void 0 === PromiseImpl && (PromiseImpl = Promise);\n var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);\n return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {\n return result.done ? result.value : iter.next();\n });\n }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, \"Generator\"), define(Gp, iteratorSymbol, function () {\n return this;\n }), define(Gp, \"toString\", function () {\n return \"[object Generator]\";\n }), exports.keys = function (val) {\n var object = Object(val),\n keys = [];\n for (var key in object) {\n keys.push(key);\n }\n return keys.reverse(), function next() {\n for (; keys.length;) {\n var key = keys.pop();\n if (key in object) return next.value = key, next.done = !1, next;\n }\n return next.done = !0, next;\n };\n }, exports.values = values, Context.prototype = {\n constructor: Context,\n reset: function reset(skipTempReset) {\n if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = \"next\", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) {\n \"t\" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);\n }\n },\n stop: function stop() {\n this.done = !0;\n var rootRecord = this.tryEntries[0].completion;\n if (\"throw\" === rootRecord.type) throw rootRecord.arg;\n return this.rval;\n },\n dispatchException: function dispatchException(exception) {\n if (this.done) throw exception;\n var context = this;\n function handle(loc, caught) {\n return record.type = \"throw\", record.arg = exception, context.next = loc, caught && (context.method = \"next\", context.arg = undefined), !!caught;\n }\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i],\n record = entry.completion;\n if (\"root\" === entry.tryLoc) return handle(\"end\");\n if (entry.tryLoc <= this.prev) {\n var hasCatch = hasOwn.call(entry, \"catchLoc\"),\n hasFinally = hasOwn.call(entry, \"finallyLoc\");\n if (hasCatch && hasFinally) {\n if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);\n if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);\n } else if (hasCatch) {\n if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);\n } else {\n if (!hasFinally) throw new Error(\"try statement without catch or finally\");\n if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);\n }\n }\n }\n },\n abrupt: function abrupt(type, arg) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.tryLoc <= this.prev && hasOwn.call(entry, \"finallyLoc\") && this.prev < entry.finallyLoc) {\n var finallyEntry = entry;\n break;\n }\n }\n finallyEntry && (\"break\" === type || \"continue\" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);\n var record = finallyEntry ? finallyEntry.completion : {};\n return record.type = type, record.arg = arg, finallyEntry ? (this.method = \"next\", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);\n },\n complete: function complete(record, afterLoc) {\n if (\"throw\" === record.type) throw record.arg;\n return \"break\" === record.type || \"continue\" === record.type ? this.next = record.arg : \"return\" === record.type ? (this.rval = this.arg = record.arg, this.method = \"return\", this.next = \"end\") : \"normal\" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;\n },\n finish: function finish(finallyLoc) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;\n }\n },\n \"catch\": function _catch(tryLoc) {\n for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n var entry = this.tryEntries[i];\n if (entry.tryLoc === tryLoc) {\n var record = entry.completion;\n if (\"throw\" === record.type) {\n var thrown = record.arg;\n resetTryEntry(entry);\n }\n return thrown;\n }\n }\n throw new Error(\"illegal catch attempt\");\n },\n delegateYield: function delegateYield(iterable, resultName, nextLoc) {\n return this.delegate = {\n iterator: values(iterable),\n resultName: resultName,\n nextLoc: nextLoc\n }, \"next\" === this.method && (this.arg = undefined), ContinueSentinel;\n }\n }, exports;\n}","export default function _setPrototypeOf(o, p) {\n _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n return _setPrototypeOf(o, p);\n}","import arrayWithHoles from \"./arrayWithHoles.js\";\nimport iterableToArrayLimit from \"./iterableToArrayLimit.js\";\nimport unsupportedIterableToArray from \"./unsupportedIterableToArray.js\";\nimport nonIterableRest from \"./nonIterableRest.js\";\nexport default function _slicedToArray(arr, i) {\n return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest();\n}","export default function _arrayWithHoles(arr) {\n if (Array.isArray(arr)) return arr;\n}","export default function _iterableToArrayLimit(arr, i) {\n var _i = null == arr ? null : \"undefined\" != typeof Symbol && arr[Symbol.iterator] || arr[\"@@iterator\"];\n if (null != _i) {\n var _s,\n _e,\n _x,\n _r,\n _arr = [],\n _n = !0,\n _d = !1;\n try {\n if (_x = (_i = _i.call(arr)).next, 0 === i) {\n if (Object(_i) !== _i) return;\n _n = !1;\n } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0) {\n ;\n }\n } catch (err) {\n _d = !0, _e = err;\n } finally {\n try {\n if (!_n && null != _i[\"return\"] && (_r = _i[\"return\"](), Object(_r) !== _r)) return;\n } finally {\n if (_d) throw _e;\n }\n }\n return _arr;\n }\n}","export default function _nonIterableRest() {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}","import arrayWithoutHoles from \"./arrayWithoutHoles.js\";\nimport iterableToArray from \"./iterableToArray.js\";\nimport unsupportedIterableToArray from \"./unsupportedIterableToArray.js\";\nimport nonIterableSpread from \"./nonIterableSpread.js\";\nexport default function _toConsumableArray(arr) {\n return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();\n}","import arrayLikeToArray from \"./arrayLikeToArray.js\";\nexport default function _arrayWithoutHoles(arr) {\n if (Array.isArray(arr)) return arrayLikeToArray(arr);\n}","export default function _iterableToArray(iter) {\n if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter);\n}","export default function _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}","import _typeof from \"./typeof.js\";\nimport toPrimitive from \"./toPrimitive.js\";\nexport default function _toPropertyKey(arg) {\n var key = toPrimitive(arg, \"string\");\n return _typeof(key) === \"symbol\" ? key : String(key);\n}","import _typeof from \"./typeof.js\";\nexport default function _toPrimitive(input, hint) {\n if (_typeof(input) !== \"object\" || input === null) return input;\n var prim = input[Symbol.toPrimitive];\n if (prim !== undefined) {\n var res = prim.call(input, hint || \"default\");\n if (_typeof(res) !== \"object\") return res;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (hint === \"string\" ? String : Number)(input);\n}","export default function _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) {\n return typeof obj;\n } : function (obj) {\n return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n }, _typeof(obj);\n}","import arrayLikeToArray from \"./arrayLikeToArray.js\";\nexport default function _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);\n}","import setPrototypeOf from \"./setPrototypeOf.js\";\nimport isNativeReflectConstruct from \"./isNativeReflectConstruct.js\";\nexport default function _construct(Parent, args, Class) {\n if (isNativeReflectConstruct()) {\n _construct = Reflect.construct.bind();\n } else {\n _construct = function _construct(Parent, args, Class) {\n var a = [null];\n a.push.apply(a, args);\n var Constructor = Function.bind.apply(Parent, a);\n var instance = new Constructor();\n if (Class) setPrototypeOf(instance, Class.prototype);\n return instance;\n };\n }\n return _construct.apply(null, arguments);\n}","import getPrototypeOf from \"./getPrototypeOf.js\";\nimport setPrototypeOf from \"./setPrototypeOf.js\";\nimport isNativeFunction from \"./isNativeFunction.js\";\nimport construct from \"./construct.js\";\nexport default function _wrapNativeSuper(Class) {\n var _cache = typeof Map === \"function\" ? new Map() : undefined;\n _wrapNativeSuper = function _wrapNativeSuper(Class) {\n if (Class === null || !isNativeFunction(Class)) return Class;\n if (typeof Class !== \"function\") {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n if (typeof _cache !== \"undefined\") {\n if (_cache.has(Class)) return _cache.get(Class);\n _cache.set(Class, Wrapper);\n }\n function Wrapper() {\n return construct(Class, arguments, getPrototypeOf(this).constructor);\n }\n Wrapper.prototype = Object.create(Class.prototype, {\n constructor: {\n value: Wrapper,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n return setPrototypeOf(Wrapper, Class);\n };\n return _wrapNativeSuper(Class);\n}","export default function _isNativeFunction(fn) {\n return Function.toString.call(fn).indexOf(\"[native code]\") !== -1;\n}","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IWindowStorage } from \"./IWindowStorage\";\n\nexport class MemoryStorage implements IWindowStorage {\n private cache: Map;\n\n constructor() {\n this.cache = new Map();\n }\n\n getItem(key: string): T | null {\n return this.cache.get(key) || null;\n }\n\n setItem(key: string, value: T): void {\n this.cache.set(key, value);\n }\n\n removeItem(key: string): void {\n this.cache.delete(key);\n }\n\n getKeys(): string[] {\n const cacheKeys: string[] = [];\n this.cache.forEach((value: T, key: string) => {\n cacheKeys.push(key);\n });\n return cacheKeys;\n }\n\n containsKey(key: string): boolean {\n return this.cache.has(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n ClientAuthErrorCodes,\n createClientAuthError,\n} from \"../error/ClientAuthError\";\nimport { NetworkResponse } from \"./NetworkManager\";\n\n/**\n * Options allowed by network request APIs.\n */\nexport type NetworkRequestOptions = {\n headers?: Record;\n body?: string;\n};\n\n/**\n * Client network interface to send backend requests.\n * @interface\n */\nexport interface INetworkModule {\n /**\n * Interface function for async network \"GET\" requests. Based on the Fetch standard: https://fetch.spec.whatwg.org/\n * @param url\n * @param requestParams\n * @param enableCaching\n */\n sendGetRequestAsync(\n url: string,\n options?: NetworkRequestOptions,\n cancellationToken?: number\n ): Promise>;\n\n /**\n * Interface function for async network \"POST\" requests. Based on the Fetch standard: https://fetch.spec.whatwg.org/\n * @param url\n * @param requestParams\n * @param enableCaching\n */\n sendPostRequestAsync(\n url: string,\n options?: NetworkRequestOptions\n ): Promise>;\n}\n\nexport const StubbedNetworkModule: INetworkModule = {\n sendGetRequestAsync: () => {\n return Promise.reject(\n createClientAuthError(ClientAuthErrorCodes.methodNotImplemented)\n );\n },\n sendPostRequestAsync: () => {\n return Promise.reject(\n createClientAuthError(ClientAuthErrorCodes.methodNotImplemented)\n );\n },\n};\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n IPerformanceClient,\n InProgressPerformanceEvent,\n} from \"./IPerformanceClient\";\nimport { IPerformanceMeasurement } from \"./IPerformanceMeasurement\";\nimport { PerformanceEvent, PerformanceEventStatus } from \"./PerformanceEvent\";\n\nexport class StubPerformanceMeasurement implements IPerformanceMeasurement {\n startMeasurement(): void {\n return;\n }\n endMeasurement(): void {\n return;\n }\n flushMeasurement(): number | null {\n return null;\n }\n}\n\nexport class StubPerformanceClient implements IPerformanceClient {\n generateId(): string {\n return \"callback-id\";\n }\n\n startMeasurement(\n measureName: string,\n correlationId?: string | undefined\n ): InProgressPerformanceEvent {\n return {\n end: () => null,\n discard: () => {},\n add: () => {},\n increment: () => {},\n event: {\n eventId: this.generateId(),\n status: PerformanceEventStatus.InProgress,\n authority: \"\",\n libraryName: \"\",\n libraryVersion: \"\",\n clientId: \"\",\n name: measureName,\n startTimeMs: Date.now(),\n correlationId: correlationId || \"\",\n },\n measurement: new StubPerformanceMeasurement(),\n };\n }\n\n startPerformanceMeasurement(): IPerformanceMeasurement {\n return new StubPerformanceMeasurement();\n }\n calculateQueuedTime(): number {\n return 0;\n }\n\n addQueueMeasurement(): void {\n return;\n }\n\n setPreQueueTime(): void {\n return;\n }\n\n endMeasurement(): PerformanceEvent | null {\n return null;\n }\n\n discardMeasurements(): void {\n return;\n }\n\n removePerformanceCallback(): boolean {\n return true;\n }\n\n addPerformanceCallback(): string {\n return \"\";\n }\n\n emitEvents(): void {\n return;\n }\n\n addFields(): void {\n return;\n }\n\n incrementFields(): void {\n return;\n }\n\n cacheEventByCorrelationId(): void {\n return;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { INavigationClient } from \"./INavigationClient\";\nimport { NavigationOptions } from \"./NavigationOptions\";\n\nexport class NavigationClient implements INavigationClient {\n /**\n * Navigates to other pages within the same web application\n * @param url\n * @param options\n */\n navigateInternal(\n url: string,\n options: NavigationOptions\n ): Promise {\n return NavigationClient.defaultNavigateWindow(url, options);\n }\n\n /**\n * Navigates to other pages outside the web application i.e. the Identity Provider\n * @param url\n * @param options\n */\n navigateExternal(\n url: string,\n options: NavigationOptions\n ): Promise {\n return NavigationClient.defaultNavigateWindow(url, options);\n }\n\n /**\n * Default navigation implementation invoked by the internal and external functions\n * @param url\n * @param options\n */\n private static defaultNavigateWindow(\n url: string,\n options: NavigationOptions\n ): Promise {\n if (options.noHistory) {\n window.location.replace(url);\n } else {\n window.location.assign(url);\n }\n\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve(true);\n }, options.timeout);\n });\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n Constants,\n INetworkModule,\n NetworkRequestOptions,\n NetworkResponse,\n} from \"@azure/msal-common\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../error/BrowserAuthError\";\nimport { HTTP_REQUEST_TYPE } from \"../utils/BrowserConstants\";\n\n/**\n * This class implements the Fetch API for GET and POST requests. See more here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n */\nexport class FetchClient implements INetworkModule {\n /**\n * Fetch Client for REST endpoints - Get request\n * @param url\n * @param headers\n * @param body\n */\n async sendGetRequestAsync(\n url: string,\n options?: NetworkRequestOptions\n ): Promise> {\n let response;\n try {\n response = await fetch(url, {\n method: HTTP_REQUEST_TYPE.GET,\n headers: this.getFetchHeaders(options),\n });\n } catch (e) {\n if (window.navigator.onLine) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.getRequestFailed\n );\n } else {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.noNetworkConnectivity\n );\n }\n }\n\n try {\n return {\n headers: this.getHeaderDict(response.headers),\n body: (await response.json()) as T,\n status: response.status,\n };\n } catch (e) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.failedToParseResponse\n );\n }\n }\n\n /**\n * Fetch Client for REST endpoints - Post request\n * @param url\n * @param headers\n * @param body\n */\n async sendPostRequestAsync(\n url: string,\n options?: NetworkRequestOptions\n ): Promise> {\n const reqBody = (options && options.body) || Constants.EMPTY_STRING;\n\n let response;\n try {\n response = await fetch(url, {\n method: HTTP_REQUEST_TYPE.POST,\n headers: this.getFetchHeaders(options),\n body: reqBody,\n });\n } catch (e) {\n if (window.navigator.onLine) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.postRequestFailed\n );\n } else {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.noNetworkConnectivity\n );\n }\n }\n\n try {\n return {\n headers: this.getHeaderDict(response.headers),\n body: (await response.json()) as T,\n status: response.status,\n };\n } catch (e) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.failedToParseResponse\n );\n }\n }\n\n /**\n * Get Fetch API Headers object from string map\n * @param inputHeaders\n */\n private getFetchHeaders(options?: NetworkRequestOptions): Headers {\n const headers = new Headers();\n if (!(options && options.headers)) {\n return headers;\n }\n const optionsHeaders = options.headers;\n Object.keys(optionsHeaders).forEach((key) => {\n headers.append(key, optionsHeaders[key]);\n });\n return headers;\n }\n\n private getHeaderDict(headers: Headers): Record {\n const headerDict: Record = {};\n headers.forEach((value: string, key: string) => {\n headerDict[key] = value;\n });\n return headerDict;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n SystemOptions,\n LoggerOptions,\n INetworkModule,\n DEFAULT_SYSTEM_OPTIONS,\n Constants,\n ProtocolMode,\n OIDCOptions,\n ServerResponseType,\n LogLevel,\n StubbedNetworkModule,\n AzureCloudInstance,\n AzureCloudOptions,\n ApplicationTelemetry,\n createClientConfigurationError,\n ClientConfigurationErrorCodes,\n IPerformanceClient,\n StubPerformanceClient,\n Logger,\n} from \"@azure/msal-common\";\nimport {\n BrowserCacheLocation,\n BrowserConstants,\n} from \"../utils/BrowserConstants\";\nimport { INavigationClient } from \"../navigation/INavigationClient\";\nimport { NavigationClient } from \"../navigation/NavigationClient\";\nimport { FetchClient } from \"../network/FetchClient\";\n\n// Default timeout for popup windows and iframes in milliseconds\nexport const DEFAULT_POPUP_TIMEOUT_MS = 60000;\nexport const DEFAULT_IFRAME_TIMEOUT_MS = 10000;\nexport const DEFAULT_REDIRECT_TIMEOUT_MS = 30000;\nexport const DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS = 2000;\n\n/**\n * Use this to configure the auth options in the Configuration object\n */\nexport type BrowserAuthOptions = {\n /**\n * Client ID of your app registered with our Application registration portal : https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview in Microsoft Identity Platform\n */\n clientId: string;\n /**\n * You can configure a specific authority, defaults to \" \" or \"https://login.microsoftonline.com/common\"\n */\n authority?: string;\n /**\n * An array of URIs that are known to be valid. Used in B2C scenarios.\n */\n knownAuthorities?: Array;\n /**\n * A string containing the cloud discovery response. Used in AAD scenarios.\n */\n cloudDiscoveryMetadata?: string;\n /**\n * A string containing the .well-known/openid-configuration endpoint response\n */\n authorityMetadata?: string;\n /**\n * The redirect URI where authentication responses can be received by your application. It must exactly match one of the redirect URIs registered in the Azure portal.\n */\n redirectUri?: string;\n /**\n * The redirect URI where the window navigates after a successful logout.\n */\n postLogoutRedirectUri?: string | null;\n /**\n * Boolean indicating whether to navigate to the original request URL after the auth server navigates to the redirect URL.\n */\n navigateToLoginRequestUrl?: boolean;\n /**\n * Array of capabilities which will be added to the claims.access_token.xms_cc request property on every network request.\n */\n clientCapabilities?: Array;\n /**\n * Enum that represents the protocol that msal follows. Used for configuring proper endpoints.\n */\n protocolMode?: ProtocolMode;\n /**\n * Enum that configures options for the OIDC protocol mode.\n */\n OIDCOptions?: OIDCOptions;\n /**\n * Enum that represents the Azure Cloud to use.\n */\n azureCloudOptions?: AzureCloudOptions;\n /**\n * Flag of whether to use the local metadata cache\n */\n skipAuthorityMetadataCache?: boolean;\n /**\n * App supports nested app auth or not; defaults to false\n */\n supportsNestedAppAuth?: boolean;\n};\n\n/** @internal */\nexport type InternalAuthOptions = Required & {\n OIDCOptions: Required;\n};\n\n/**\n * Use this to configure the below cache configuration options:\n */\nexport type CacheOptions = {\n /**\n * Used to specify the cacheLocation user wants to set. Valid values are \"localStorage\", \"sessionStorage\" and \"memoryStorage\".\n */\n cacheLocation?: BrowserCacheLocation | string;\n /**\n * Used to specify the temporaryCacheLocation user wants to set. Valid values are \"localStorage\", \"sessionStorage\" and \"memoryStorage\".\n */\n temporaryCacheLocation?: BrowserCacheLocation | string;\n /**\n * If set, MSAL stores the auth request state required for validation of the auth flows in the browser cookies. By default this flag is set to false.\n */\n storeAuthStateInCookie?: boolean;\n /**\n * If set, MSAL sets the \"Secure\" flag on cookies so they can only be sent over HTTPS. By default this flag is set to false.\n */\n secureCookies?: boolean;\n /**\n * If set, MSAL will attempt to migrate cache entries from older versions on initialization. By default this flag is set to true if cacheLocation is localStorage, otherwise false.\n */\n cacheMigrationEnabled?: boolean;\n /**\n * Flag that determines whether access tokens are stored based on requested claims\n */\n claimsBasedCachingEnabled?: boolean;\n};\n\nexport type BrowserSystemOptions = SystemOptions & {\n /**\n * Used to initialize the Logger object (See ClientConfiguration.ts)\n */\n loggerOptions?: LoggerOptions;\n /**\n * Network interface implementation\n */\n networkClient?: INetworkModule;\n /**\n * Override the methods used to navigate to other webpages. Particularly useful if you are using a client-side router\n */\n navigationClient?: INavigationClient;\n /**\n * Sets the timeout for waiting for a response hash in a popup. Will take precedence over loadFrameTimeout if both are set.\n */\n windowHashTimeout?: number;\n /**\n * Sets the timeout for waiting for a response hash in an iframe. Will take precedence over loadFrameTimeout if both are set.\n */\n iframeHashTimeout?: number;\n /**\n * Sets the timeout for waiting for a response hash in an iframe or popup\n */\n loadFrameTimeout?: number;\n /**\n * Maximum time the library should wait for a frame to load\n * @deprecated This was previously needed for older browsers which are no longer supported by MSAL.js. This option will be removed in the next major version\n */\n navigateFrameWait?: number;\n /**\n * Time to wait for redirection to occur before resolving promise\n */\n redirectNavigationTimeout?: number;\n /**\n * Sets whether popups are opened asynchronously. By default, this flag is set to false. When set to false, blank popups are opened before anything else happens. When set to true, popups are opened when making the network request.\n */\n asyncPopups?: boolean;\n /**\n * Flag to enable redirect opertaions when the app is rendered in an iframe (to support scenarios such as embedded B2C login).\n */\n allowRedirectInIframe?: boolean;\n /**\n * Flag to enable native broker support (e.g. acquiring tokens from WAM on Windows)\n */\n allowNativeBroker?: boolean;\n /**\n * Sets the timeout for waiting for the native broker handshake to resolve\n */\n nativeBrokerHandshakeTimeout?: number;\n /**\n * Sets the interval length in milliseconds for polling the location attribute in popup windows (default is 30ms)\n */\n pollIntervalMilliseconds?: number;\n};\n\n/**\n * Telemetry Options\n */\nexport type BrowserTelemetryOptions = {\n /**\n * Telemetry information sent on request\n * - appName: Unique string name of an application\n * - appVersion: Version of the application using MSAL\n */\n application?: ApplicationTelemetry;\n\n client?: IPerformanceClient;\n};\n\n/**\n * This object allows you to configure important elements of MSAL functionality and is passed into the constructor of PublicClientApplication\n */\nexport type Configuration = {\n /**\n * This is where you configure auth elements like clientID, authority used for authenticating against the Microsoft Identity Platform\n */\n auth: BrowserAuthOptions;\n /**\n * This is where you configure cache location and whether to store cache in cookies\n */\n cache?: CacheOptions;\n /**\n * This is where you can configure the network client, logger, token renewal offset\n */\n system?: BrowserSystemOptions;\n /**\n * This is where you can configure telemetry data and options\n */\n telemetry?: BrowserTelemetryOptions;\n};\n\n/** @internal */\nexport type BrowserConfiguration = {\n auth: InternalAuthOptions;\n cache: Required;\n system: Required;\n telemetry: Required;\n};\n\n/**\n * MSAL function that sets the default options when not explicitly configured from app developer\n *\n * @param auth\n * @param cache\n * @param system\n *\n * @returns Configuration object\n */\nexport function buildConfiguration(\n {\n auth: userInputAuth,\n cache: userInputCache,\n system: userInputSystem,\n telemetry: userInputTelemetry,\n }: Configuration,\n isBrowserEnvironment: boolean\n): BrowserConfiguration {\n // Default auth options for browser\n const DEFAULT_AUTH_OPTIONS: InternalAuthOptions = {\n clientId: Constants.EMPTY_STRING,\n authority: `${Constants.DEFAULT_AUTHORITY}`,\n knownAuthorities: [],\n cloudDiscoveryMetadata: Constants.EMPTY_STRING,\n authorityMetadata: Constants.EMPTY_STRING,\n redirectUri: Constants.EMPTY_STRING,\n postLogoutRedirectUri: Constants.EMPTY_STRING,\n navigateToLoginRequestUrl: true,\n clientCapabilities: [],\n protocolMode: ProtocolMode.AAD,\n OIDCOptions: {\n serverResponseType: ServerResponseType.FRAGMENT,\n defaultScopes: [\n Constants.OPENID_SCOPE,\n Constants.PROFILE_SCOPE,\n Constants.OFFLINE_ACCESS_SCOPE,\n ],\n },\n azureCloudOptions: {\n azureCloudInstance: AzureCloudInstance.None,\n tenant: Constants.EMPTY_STRING,\n },\n skipAuthorityMetadataCache: false,\n supportsNestedAppAuth: false,\n };\n\n // Default cache options for browser\n const DEFAULT_CACHE_OPTIONS: Required = {\n cacheLocation: BrowserCacheLocation.SessionStorage,\n temporaryCacheLocation: BrowserCacheLocation.SessionStorage,\n storeAuthStateInCookie: false,\n secureCookies: false,\n // Default cache migration to true if cache location is localStorage since entries are preserved across tabs/windows. Migration has little to no benefit in sessionStorage and memoryStorage\n cacheMigrationEnabled:\n userInputCache &&\n userInputCache.cacheLocation === BrowserCacheLocation.LocalStorage\n ? true\n : false,\n claimsBasedCachingEnabled: false,\n };\n\n // Default logger options for browser\n const DEFAULT_LOGGER_OPTIONS: LoggerOptions = {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n loggerCallback: (): void => {\n // allow users to not set logger call back\n },\n logLevel: LogLevel.Info,\n piiLoggingEnabled: false,\n };\n\n // Default system options for browser\n const DEFAULT_BROWSER_SYSTEM_OPTIONS: Required = {\n ...DEFAULT_SYSTEM_OPTIONS,\n loggerOptions: DEFAULT_LOGGER_OPTIONS,\n networkClient: isBrowserEnvironment\n ? new FetchClient()\n : StubbedNetworkModule,\n navigationClient: new NavigationClient(),\n loadFrameTimeout: 0,\n // If loadFrameTimeout is provided, use that as default.\n windowHashTimeout:\n userInputSystem?.loadFrameTimeout || DEFAULT_POPUP_TIMEOUT_MS,\n iframeHashTimeout:\n userInputSystem?.loadFrameTimeout || DEFAULT_IFRAME_TIMEOUT_MS,\n navigateFrameWait: 0,\n redirectNavigationTimeout: DEFAULT_REDIRECT_TIMEOUT_MS,\n asyncPopups: false,\n allowRedirectInIframe: false,\n allowNativeBroker: false,\n nativeBrokerHandshakeTimeout:\n userInputSystem?.nativeBrokerHandshakeTimeout ||\n DEFAULT_NATIVE_BROKER_HANDSHAKE_TIMEOUT_MS,\n pollIntervalMilliseconds: BrowserConstants.DEFAULT_POLL_INTERVAL_MS,\n };\n\n const providedSystemOptions: Required = {\n ...DEFAULT_BROWSER_SYSTEM_OPTIONS,\n ...userInputSystem,\n loggerOptions: userInputSystem?.loggerOptions || DEFAULT_LOGGER_OPTIONS,\n };\n\n const DEFAULT_TELEMETRY_OPTIONS: Required = {\n application: {\n appName: Constants.EMPTY_STRING,\n appVersion: Constants.EMPTY_STRING,\n },\n client: new StubPerformanceClient(),\n };\n\n // Throw an error if user has set OIDCOptions without being in OIDC protocol mode\n if (\n userInputAuth?.protocolMode !== ProtocolMode.OIDC &&\n userInputAuth?.OIDCOptions\n ) {\n const logger = new Logger(providedSystemOptions.loggerOptions);\n logger.warning(\n JSON.stringify(\n createClientConfigurationError(\n ClientConfigurationErrorCodes.cannotSetOIDCOptions\n )\n )\n );\n }\n\n // Throw an error if user has set allowNativeBroker to true without being in AAD protocol mode\n if (\n userInputAuth?.protocolMode &&\n userInputAuth.protocolMode !== ProtocolMode.AAD &&\n providedSystemOptions?.allowNativeBroker\n ) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.cannotAllowNativeBroker\n );\n }\n\n const overlayedConfig: BrowserConfiguration = {\n auth: {\n ...DEFAULT_AUTH_OPTIONS,\n ...userInputAuth,\n OIDCOptions: {\n ...DEFAULT_AUTH_OPTIONS.OIDCOptions,\n ...userInputAuth?.OIDCOptions,\n },\n },\n cache: { ...DEFAULT_CACHE_OPTIONS, ...userInputCache },\n system: providedSystemOptions,\n telemetry: { ...DEFAULT_TELEMETRY_OPTIONS, ...userInputTelemetry },\n };\n\n return overlayedConfig;\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Tenant Discovery Response which contains the relevant OAuth endpoints and data needed for authentication and authorization.\n */\nexport type OpenIdConfigResponse = {\n authorization_endpoint: string;\n token_endpoint: string;\n end_session_endpoint?: string;\n issuer: string;\n jwks_uri: string;\n};\n\nexport function isOpenIdConfigResponse(response: object): boolean {\n return (\n response.hasOwnProperty(\"authorization_endpoint\") &&\n response.hasOwnProperty(\"token_endpoint\") &&\n response.hasOwnProperty(\"issuer\") &&\n response.hasOwnProperty(\"jwks_uri\")\n );\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { CloudDiscoveryMetadata } from \"./CloudDiscoveryMetadata\";\n\n/**\n * The OpenID Configuration Endpoint Response type. Used by the authority class to get relevant OAuth endpoints.\n */\nexport type CloudInstanceDiscoveryResponse = {\n tenant_discovery_endpoint: string;\n metadata: Array;\n};\n\nexport function isCloudInstanceDiscoveryResponse(response: object): boolean {\n return (\n response.hasOwnProperty(\"tenant_discovery_endpoint\") &&\n response.hasOwnProperty(\"metadata\")\n );\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * The OpenID Configuration Endpoint Response type. Used by the authority class to get relevant OAuth endpoints.\n */\nexport type CloudInstanceDiscoveryErrorResponse = {\n error: String;\n error_description: String;\n error_codes?: Array;\n timestamp?: String;\n trace_id?: String;\n correlation_id?: String;\n error_uri?: String;\n};\n\nexport function isCloudInstanceDiscoveryErrorResponse(\n response: object\n): boolean {\n return (\n response.hasOwnProperty(\"error\") &&\n response.hasOwnProperty(\"error_description\")\n );\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { Logger } from \"../logger/Logger\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\n\n/**\n * Wraps a function with a performance measurement.\n * Usage: invoke(functionToCall, performanceClient, \"EventName\", \"correlationId\")(...argsToPassToFunction)\n * @param callback\n * @param eventName\n * @param logger\n * @param telemetryClient\n * @param correlationId\n * @returns\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const invoke = , U>(\n callback: (...args: T) => U,\n eventName: string,\n logger: Logger,\n telemetryClient?: IPerformanceClient,\n correlationId?: string\n) => {\n return (...args: T): U => {\n logger.trace(`Executing function ${eventName}`);\n const inProgressEvent = telemetryClient?.startMeasurement(\n eventName,\n correlationId\n );\n if (correlationId) {\n // Track number of times this API is called in a single request\n const eventCount = eventName + \"CallCount\";\n telemetryClient?.incrementFields(\n { [eventCount]: 1 },\n correlationId\n );\n }\n try {\n const result = callback(...args);\n inProgressEvent?.end({\n success: true,\n });\n logger.trace(`Returning result from ${eventName}`);\n return result;\n } catch (e) {\n logger.trace(`Error occurred in ${eventName}`);\n try {\n logger.trace(JSON.stringify(e));\n } catch (e) {\n logger.trace(\"Unable to print error message.\");\n }\n inProgressEvent?.end({\n success: false,\n });\n throw e;\n }\n };\n};\n\n/**\n * Wraps an async function with a performance measurement.\n * Usage: invokeAsync(functionToCall, performanceClient, \"EventName\", \"correlationId\")(...argsToPassToFunction)\n * @param callback\n * @param eventName\n * @param logger\n * @param telemetryClient\n * @param correlationId\n * @returns\n * @internal\n *\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const invokeAsync = , U>(\n callback: (...args: T) => Promise,\n eventName: string,\n logger: Logger,\n telemetryClient?: IPerformanceClient,\n correlationId?: string\n) => {\n return (...args: T): Promise => {\n logger.trace(`Executing function ${eventName}`);\n const inProgressEvent = telemetryClient?.startMeasurement(\n eventName,\n correlationId\n );\n if (correlationId) {\n // Track number of times this API is called in a single request\n const eventCount = eventName + \"CallCount\";\n telemetryClient?.incrementFields(\n { [eventCount]: 1 },\n correlationId\n );\n }\n telemetryClient?.setPreQueueTime(eventName, correlationId);\n return callback(...args)\n .then((response) => {\n logger.trace(`Returning result from ${eventName}`);\n inProgressEvent?.end({\n success: true,\n });\n return response;\n })\n .catch((e) => {\n logger.trace(`Error occurred in ${eventName}`);\n try {\n logger.trace(JSON.stringify(e));\n } catch (e) {\n logger.trace(\"Unable to print error message.\");\n }\n inProgressEvent?.end({\n success: false,\n });\n throw e;\n });\n };\n};\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { INetworkModule } from \"../network/INetworkModule\";\nimport { NetworkResponse } from \"../network/NetworkManager\";\nimport { IMDSBadResponse } from \"../response/IMDSBadResponse\";\nimport {\n Constants,\n RegionDiscoverySources,\n ResponseCodes,\n} from \"../utils/Constants\";\nimport { RegionDiscoveryMetadata } from \"./RegionDiscoveryMetadata\";\nimport { ImdsOptions } from \"./ImdsOptions\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { invokeAsync } from \"../utils/FunctionWrappers\";\nimport { Logger } from \"../logger/Logger\";\n\nexport class RegionDiscovery {\n // Network interface to make requests with.\n protected networkInterface: INetworkModule;\n // Logger\n private logger: Logger;\n // Performance client\n protected performanceClient: IPerformanceClient | undefined;\n // CorrelationId\n protected correlationId: string | undefined;\n // Options for the IMDS endpoint request\n protected static IMDS_OPTIONS: ImdsOptions = {\n headers: {\n Metadata: \"true\",\n },\n };\n\n constructor(\n networkInterface: INetworkModule,\n logger: Logger,\n performanceClient?: IPerformanceClient,\n correlationId?: string\n ) {\n this.networkInterface = networkInterface;\n this.logger = logger;\n this.performanceClient = performanceClient;\n this.correlationId = correlationId;\n }\n\n /**\n * Detect the region from the application's environment.\n *\n * @returns Promise\n */\n public async detectRegion(\n environmentRegion: string | undefined,\n regionDiscoveryMetadata: RegionDiscoveryMetadata\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RegionDiscoveryDetectRegion,\n this.correlationId\n );\n\n // Initialize auto detected region with the region from the envrionment\n let autodetectedRegionName = environmentRegion;\n\n // Check if a region was detected from the environment, if not, attempt to get the region from IMDS\n if (!autodetectedRegionName) {\n const options = RegionDiscovery.IMDS_OPTIONS;\n\n try {\n const localIMDSVersionResponse = await invokeAsync(\n this.getRegionFromIMDS.bind(this),\n PerformanceEvents.RegionDiscoveryGetRegionFromIMDS,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(Constants.IMDS_VERSION, options);\n if (\n localIMDSVersionResponse.status ===\n ResponseCodes.httpSuccess\n ) {\n autodetectedRegionName = localIMDSVersionResponse.body;\n regionDiscoveryMetadata.region_source =\n RegionDiscoverySources.IMDS;\n }\n\n // If the response using the local IMDS version failed, try to fetch the current version of IMDS and retry.\n if (\n localIMDSVersionResponse.status ===\n ResponseCodes.httpBadRequest\n ) {\n const currentIMDSVersion = await invokeAsync(\n this.getCurrentVersion.bind(this),\n PerformanceEvents.RegionDiscoveryGetCurrentVersion,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(options);\n if (!currentIMDSVersion) {\n regionDiscoveryMetadata.region_source =\n RegionDiscoverySources.FAILED_AUTO_DETECTION;\n return null;\n }\n\n const currentIMDSVersionResponse = await invokeAsync(\n this.getRegionFromIMDS.bind(this),\n PerformanceEvents.RegionDiscoveryGetRegionFromIMDS,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(currentIMDSVersion, options);\n if (\n currentIMDSVersionResponse.status ===\n ResponseCodes.httpSuccess\n ) {\n autodetectedRegionName =\n currentIMDSVersionResponse.body;\n regionDiscoveryMetadata.region_source =\n RegionDiscoverySources.IMDS;\n }\n }\n } catch (e) {\n regionDiscoveryMetadata.region_source =\n RegionDiscoverySources.FAILED_AUTO_DETECTION;\n return null;\n }\n } else {\n regionDiscoveryMetadata.region_source =\n RegionDiscoverySources.ENVIRONMENT_VARIABLE;\n }\n\n // If no region was auto detected from the environment or from the IMDS endpoint, mark the attempt as a FAILED_AUTO_DETECTION\n if (!autodetectedRegionName) {\n regionDiscoveryMetadata.region_source =\n RegionDiscoverySources.FAILED_AUTO_DETECTION;\n }\n\n return autodetectedRegionName || null;\n }\n\n /**\n * Make the call to the IMDS endpoint\n *\n * @param imdsEndpointUrl\n * @returns Promise>\n */\n private async getRegionFromIMDS(\n version: string,\n options: ImdsOptions\n ): Promise> {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RegionDiscoveryGetRegionFromIMDS,\n this.correlationId\n );\n return this.networkInterface.sendGetRequestAsync(\n `${Constants.IMDS_ENDPOINT}?api-version=${version}&format=text`,\n options,\n Constants.IMDS_TIMEOUT\n );\n }\n\n /**\n * Get the most recent version of the IMDS endpoint available\n *\n * @returns Promise\n */\n private async getCurrentVersion(\n options: ImdsOptions\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RegionDiscoveryGetCurrentVersion,\n this.correlationId\n );\n try {\n const response =\n await this.networkInterface.sendGetRequestAsync(\n `${Constants.IMDS_ENDPOINT}?format=json`,\n options\n );\n\n // When IMDS endpoint is called without the api version query param, bad request response comes back with latest version.\n if (\n response.status === ResponseCodes.httpBadRequest &&\n response.body &&\n response.body[\"newest-versions\"] &&\n response.body[\"newest-versions\"].length > 0\n ) {\n return response.body[\"newest-versions\"][0];\n }\n\n return null;\n } catch (e) {\n return null;\n }\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { AuthorityType } from \"./AuthorityType\";\nimport {\n isOpenIdConfigResponse,\n OpenIdConfigResponse,\n} from \"./OpenIdConfigResponse\";\nimport { UrlString } from \"../url/UrlString\";\nimport { IUri } from \"../url/IUri\";\nimport {\n createClientAuthError,\n ClientAuthErrorCodes,\n} from \"../error/ClientAuthError\";\nimport { INetworkModule } from \"../network/INetworkModule\";\nimport {\n AADAuthorityConstants,\n AuthorityMetadataSource,\n Constants,\n RegionDiscoveryOutcomes,\n} from \"../utils/Constants\";\nimport {\n EndpointMetadata,\n getCloudDiscoveryMetadataFromHardcodedValues,\n getCloudDiscoveryMetadataFromNetworkResponse,\n InstanceDiscoveryMetadataAliases,\n} from \"./AuthorityMetadata\";\nimport {\n createClientConfigurationError,\n ClientConfigurationErrorCodes,\n} from \"../error/ClientConfigurationError\";\nimport { ProtocolMode } from \"./ProtocolMode\";\nimport { ICacheManager } from \"../cache/interface/ICacheManager\";\nimport { AuthorityMetadataEntity } from \"../cache/entities/AuthorityMetadataEntity\";\nimport {\n AuthorityOptions,\n AzureCloudInstance,\n StaticAuthorityOptions,\n} from \"./AuthorityOptions\";\nimport {\n CloudInstanceDiscoveryResponse,\n isCloudInstanceDiscoveryResponse,\n} from \"./CloudInstanceDiscoveryResponse\";\nimport {\n CloudInstanceDiscoveryErrorResponse,\n isCloudInstanceDiscoveryErrorResponse,\n} from \"./CloudInstanceDiscoveryErrorResponse\";\nimport { CloudDiscoveryMetadata } from \"./CloudDiscoveryMetadata\";\nimport { RegionDiscovery } from \"./RegionDiscovery\";\nimport { RegionDiscoveryMetadata } from \"./RegionDiscoveryMetadata\";\nimport { ImdsOptions } from \"./ImdsOptions\";\nimport { AzureCloudOptions } from \"../config/ClientConfiguration\";\nimport { Logger } from \"../logger/Logger\";\nimport { AuthError } from \"../error/AuthError\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { invokeAsync } from \"../utils/FunctionWrappers\";\nimport * as CacheHelpers from \"../cache/utils/CacheHelpers\";\n\n/**\n * The authority class validates the authority URIs used by the user, and retrieves the OpenID Configuration Data from the\n * endpoint. It will store the pertinent config data in this object for use during token calls.\n * @internal\n */\nexport class Authority {\n // Canonical authority url string\n private _canonicalAuthority: UrlString;\n // Canonicaly authority url components\n private _canonicalAuthorityUrlComponents: IUri | null;\n // Network interface to make requests with.\n protected networkInterface: INetworkModule;\n // Cache Manager to cache network responses\n protected cacheManager: ICacheManager;\n // Protocol mode to construct endpoints\n private authorityOptions: AuthorityOptions;\n // Authority metadata\n private metadata: AuthorityMetadataEntity;\n // Region discovery service\n private regionDiscovery: RegionDiscovery;\n // Region discovery metadata\n public regionDiscoveryMetadata: RegionDiscoveryMetadata;\n // Logger object\n private logger: Logger;\n // Performance client\n protected performanceClient: IPerformanceClient | undefined;\n // Correlation Id\n protected correlationId: string;\n // Reserved tenant domain names that will not be replaced with tenant id\n private static reservedTenantDomains: Set = new Set([\n \"{tenant}\",\n \"{tenantid}\",\n AADAuthorityConstants.COMMON,\n AADAuthorityConstants.CONSUMERS,\n AADAuthorityConstants.ORGANIZATIONS,\n ]);\n\n constructor(\n authority: string,\n networkInterface: INetworkModule,\n cacheManager: ICacheManager,\n authorityOptions: AuthorityOptions,\n logger: Logger,\n correlationId: string,\n performanceClient?: IPerformanceClient\n ) {\n this.canonicalAuthority = authority;\n this._canonicalAuthority.validateAsUri();\n this.networkInterface = networkInterface;\n this.cacheManager = cacheManager;\n this.authorityOptions = authorityOptions;\n this.regionDiscoveryMetadata = {\n region_used: undefined,\n region_source: undefined,\n region_outcome: undefined,\n };\n this.logger = logger;\n this.performanceClient = performanceClient;\n this.correlationId = correlationId;\n this.regionDiscovery = new RegionDiscovery(\n networkInterface,\n this.logger,\n this.performanceClient,\n this.correlationId\n );\n }\n\n /**\n * Get {@link AuthorityType}\n * @param authorityUri {@link IUri}\n * @private\n */\n private getAuthorityType(authorityUri: IUri): AuthorityType {\n // CIAM auth url pattern is being standardized as: .ciamlogin.com\n if (authorityUri.HostNameAndPort.endsWith(Constants.CIAM_AUTH_URL)) {\n return AuthorityType.Ciam;\n }\n\n const pathSegments = authorityUri.PathSegments;\n if (pathSegments.length) {\n switch (pathSegments[0].toLowerCase()) {\n case Constants.ADFS:\n return AuthorityType.Adfs;\n case Constants.DSTS:\n return AuthorityType.Dsts;\n default:\n break;\n }\n }\n return AuthorityType.Default;\n }\n\n // See above for AuthorityType\n public get authorityType(): AuthorityType {\n return this.getAuthorityType(this.canonicalAuthorityUrlComponents);\n }\n\n /**\n * ProtocolMode enum representing the way endpoints are constructed.\n */\n public get protocolMode(): ProtocolMode {\n return this.authorityOptions.protocolMode;\n }\n\n /**\n * Returns authorityOptions which can be used to reinstantiate a new authority instance\n */\n public get options(): AuthorityOptions {\n return this.authorityOptions;\n }\n\n /**\n * A URL that is the authority set by the developer\n */\n public get canonicalAuthority(): string {\n return this._canonicalAuthority.urlString;\n }\n\n /**\n * Sets canonical authority.\n */\n public set canonicalAuthority(url: string) {\n this._canonicalAuthority = new UrlString(url);\n this._canonicalAuthority.validateAsUri();\n this._canonicalAuthorityUrlComponents = null;\n }\n\n /**\n * Get authority components.\n */\n public get canonicalAuthorityUrlComponents(): IUri {\n if (!this._canonicalAuthorityUrlComponents) {\n this._canonicalAuthorityUrlComponents =\n this._canonicalAuthority.getUrlComponents();\n }\n\n return this._canonicalAuthorityUrlComponents;\n }\n\n /**\n * Get hostname and port i.e. login.microsoftonline.com\n */\n public get hostnameAndPort(): string {\n return this.canonicalAuthorityUrlComponents.HostNameAndPort.toLowerCase();\n }\n\n /**\n * Get tenant for authority.\n */\n public get tenant(): string {\n return this.canonicalAuthorityUrlComponents.PathSegments[0];\n }\n\n /**\n * OAuth /authorize endpoint for requests\n */\n public get authorizationEndpoint(): string {\n if (this.discoveryComplete()) {\n return this.replacePath(this.metadata.authorization_endpoint);\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n /**\n * OAuth /token endpoint for requests\n */\n public get tokenEndpoint(): string {\n if (this.discoveryComplete()) {\n return this.replacePath(this.metadata.token_endpoint);\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n public get deviceCodeEndpoint(): string {\n if (this.discoveryComplete()) {\n return this.replacePath(\n this.metadata.token_endpoint.replace(\"/token\", \"/devicecode\")\n );\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n /**\n * OAuth logout endpoint for requests\n */\n public get endSessionEndpoint(): string {\n if (this.discoveryComplete()) {\n // ROPC policies may not have end_session_endpoint set\n if (!this.metadata.end_session_endpoint) {\n throw createClientAuthError(\n ClientAuthErrorCodes.endSessionEndpointNotSupported\n );\n }\n return this.replacePath(this.metadata.end_session_endpoint);\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n /**\n * OAuth issuer for requests\n */\n public get selfSignedJwtAudience(): string {\n if (this.discoveryComplete()) {\n return this.replacePath(this.metadata.issuer);\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n /**\n * Jwks_uri for token signing keys\n */\n public get jwksUri(): string {\n if (this.discoveryComplete()) {\n return this.replacePath(this.metadata.jwks_uri);\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n /**\n * Returns a flag indicating that tenant name can be replaced in authority {@link IUri}\n * @param authorityUri {@link IUri}\n * @private\n */\n private canReplaceTenant(authorityUri: IUri): boolean {\n return (\n authorityUri.PathSegments.length === 1 &&\n !Authority.reservedTenantDomains.has(\n authorityUri.PathSegments[0]\n ) &&\n this.getAuthorityType(authorityUri) === AuthorityType.Default &&\n this.protocolMode === ProtocolMode.AAD\n );\n }\n\n /**\n * Replaces tenant in url path with current tenant. Defaults to common.\n * @param urlString\n */\n private replaceTenant(urlString: string): string {\n return urlString.replace(/{tenant}|{tenantid}/g, this.tenant);\n }\n\n /**\n * Replaces path such as tenant or policy with the current tenant or policy.\n * @param urlString\n */\n private replacePath(urlString: string): string {\n let endpoint = urlString;\n const cachedAuthorityUrl = new UrlString(\n this.metadata.canonical_authority\n );\n const cachedAuthorityUrlComponents =\n cachedAuthorityUrl.getUrlComponents();\n const cachedAuthorityParts = cachedAuthorityUrlComponents.PathSegments;\n const currentAuthorityParts =\n this.canonicalAuthorityUrlComponents.PathSegments;\n\n currentAuthorityParts.forEach((currentPart, index) => {\n let cachedPart = cachedAuthorityParts[index];\n if (\n index === 0 &&\n this.canReplaceTenant(cachedAuthorityUrlComponents)\n ) {\n const tenantId = new UrlString(\n this.metadata.authorization_endpoint\n ).getUrlComponents().PathSegments[0];\n /**\n * Check if AAD canonical authority contains tenant domain name, for example \"testdomain.onmicrosoft.com\",\n * by comparing its first path segment to the corresponding authorization endpoint path segment, which is\n * always resolved with tenant id by OIDC.\n */\n if (cachedPart !== tenantId) {\n this.logger.verbose(\n `Replacing tenant domain name ${cachedPart} with id ${tenantId}`\n );\n cachedPart = tenantId;\n }\n }\n if (currentPart !== cachedPart) {\n endpoint = endpoint.replace(\n `/${cachedPart}/`,\n `/${currentPart}/`\n );\n }\n });\n\n return this.replaceTenant(endpoint);\n }\n\n /**\n * The default open id configuration endpoint for any canonical authority.\n */\n protected get defaultOpenIdConfigurationEndpoint(): string {\n const canonicalAuthorityHost = this.hostnameAndPort;\n if (\n this.canonicalAuthority.endsWith(\"v2.0/\") ||\n this.authorityType === AuthorityType.Adfs ||\n (this.protocolMode !== ProtocolMode.AAD &&\n !this.isAliasOfKnownMicrosoftAuthority(canonicalAuthorityHost))\n ) {\n return `${this.canonicalAuthority}.well-known/openid-configuration`;\n }\n return `${this.canonicalAuthority}v2.0/.well-known/openid-configuration`;\n }\n\n /**\n * Boolean that returns whethr or not tenant discovery has been completed.\n */\n discoveryComplete(): boolean {\n return !!this.metadata;\n }\n\n /**\n * Perform endpoint discovery to discover aliases, preferred_cache, preferred_network\n * and the /authorize, /token and logout endpoints.\n */\n public async resolveEndpointsAsync(): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityResolveEndpointsAsync,\n this.correlationId\n );\n\n const metadataEntity = this.getCurrentMetadataEntity();\n\n const cloudDiscoverySource = await invokeAsync(\n this.updateCloudDiscoveryMetadata.bind(this),\n PerformanceEvents.AuthorityUpdateCloudDiscoveryMetadata,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(metadataEntity);\n this.canonicalAuthority = this.canonicalAuthority.replace(\n this.hostnameAndPort,\n metadataEntity.preferred_network\n );\n const endpointSource = await invokeAsync(\n this.updateEndpointMetadata.bind(this),\n PerformanceEvents.AuthorityUpdateEndpointMetadata,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(metadataEntity);\n this.updateCachedMetadata(metadataEntity, cloudDiscoverySource, {\n source: endpointSource,\n });\n this.performanceClient?.addFields(\n {\n cloudDiscoverySource: cloudDiscoverySource,\n authorityEndpointSource: endpointSource,\n },\n this.correlationId\n );\n }\n\n /**\n * Returns metadata entity from cache if it exists, otherwiser returns a new metadata entity built\n * from the configured canonical authority\n * @returns\n */\n private getCurrentMetadataEntity(): AuthorityMetadataEntity {\n let metadataEntity: AuthorityMetadataEntity | null =\n this.cacheManager.getAuthorityMetadataByAlias(this.hostnameAndPort);\n\n if (!metadataEntity) {\n metadataEntity = {\n aliases: [],\n preferred_cache: this.hostnameAndPort,\n preferred_network: this.hostnameAndPort,\n canonical_authority: this.canonicalAuthority,\n authorization_endpoint: \"\",\n token_endpoint: \"\",\n end_session_endpoint: \"\",\n issuer: \"\",\n aliasesFromNetwork: false,\n endpointsFromNetwork: false,\n expiresAt: CacheHelpers.generateAuthorityMetadataExpiresAt(),\n jwks_uri: \"\",\n };\n }\n return metadataEntity;\n }\n\n /**\n * Updates cached metadata based on metadata source and sets the instance's metadata\n * property to the same value\n * @param metadataEntity\n * @param cloudDiscoverySource\n * @param endpointMetadataResult\n */\n private updateCachedMetadata(\n metadataEntity: AuthorityMetadataEntity,\n cloudDiscoverySource: AuthorityMetadataSource | null,\n endpointMetadataResult: {\n source: AuthorityMetadataSource;\n metadata?: OpenIdConfigResponse;\n } | null\n ): void {\n if (\n cloudDiscoverySource !== AuthorityMetadataSource.CACHE &&\n endpointMetadataResult?.source !== AuthorityMetadataSource.CACHE\n ) {\n // Reset the expiration time unless both values came from a successful cache lookup\n metadataEntity.expiresAt =\n CacheHelpers.generateAuthorityMetadataExpiresAt();\n metadataEntity.canonical_authority = this.canonicalAuthority;\n }\n\n const cacheKey = this.cacheManager.generateAuthorityMetadataCacheKey(\n metadataEntity.preferred_cache\n );\n this.cacheManager.setAuthorityMetadata(cacheKey, metadataEntity);\n this.metadata = metadataEntity;\n }\n\n /**\n * Update AuthorityMetadataEntity with new endpoints and return where the information came from\n * @param metadataEntity\n */\n private async updateEndpointMetadata(\n metadataEntity: AuthorityMetadataEntity\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityUpdateEndpointMetadata,\n this.correlationId\n );\n\n const localMetadata =\n this.updateEndpointMetadataFromLocalSources(metadataEntity);\n\n // Further update may be required for hardcoded metadata if regional metadata is preferred\n if (localMetadata) {\n if (\n localMetadata.source ===\n AuthorityMetadataSource.HARDCODED_VALUES\n ) {\n // If the user prefers to use an azure region replace the global endpoints with regional information.\n if (\n this.authorityOptions.azureRegionConfiguration?.azureRegion\n ) {\n if (localMetadata.metadata) {\n const hardcodedMetadata = await invokeAsync(\n this.updateMetadataWithRegionalInformation.bind(\n this\n ),\n PerformanceEvents.AuthorityUpdateMetadataWithRegionalInformation,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(localMetadata.metadata);\n CacheHelpers.updateAuthorityEndpointMetadata(\n metadataEntity,\n hardcodedMetadata,\n false\n );\n metadataEntity.canonical_authority =\n this.canonicalAuthority;\n }\n }\n }\n return localMetadata.source;\n }\n\n // Get metadata from network if local sources aren't available\n let metadata = await invokeAsync(\n this.getEndpointMetadataFromNetwork.bind(this),\n PerformanceEvents.AuthorityGetEndpointMetadataFromNetwork,\n this.logger,\n this.performanceClient,\n this.correlationId\n )();\n if (metadata) {\n // If the user prefers to use an azure region replace the global endpoints with regional information.\n if (this.authorityOptions.azureRegionConfiguration?.azureRegion) {\n metadata = await invokeAsync(\n this.updateMetadataWithRegionalInformation.bind(this),\n PerformanceEvents.AuthorityUpdateMetadataWithRegionalInformation,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(metadata);\n }\n\n CacheHelpers.updateAuthorityEndpointMetadata(\n metadataEntity,\n metadata,\n true\n );\n return AuthorityMetadataSource.NETWORK;\n } else {\n // Metadata could not be obtained from the config, cache, network or hardcoded values\n throw createClientAuthError(\n ClientAuthErrorCodes.openIdConfigError,\n this.defaultOpenIdConfigurationEndpoint\n );\n }\n }\n\n /**\n * Updates endpoint metadata from local sources and returns where the information was retrieved from and the metadata config\n * response if the source is hardcoded metadata\n * @param metadataEntity\n * @returns\n */\n private updateEndpointMetadataFromLocalSources(\n metadataEntity: AuthorityMetadataEntity\n ): {\n source: AuthorityMetadataSource;\n metadata?: OpenIdConfigResponse;\n } | null {\n this.logger.verbose(\n \"Attempting to get endpoint metadata from authority configuration\"\n );\n const configMetadata = this.getEndpointMetadataFromConfig();\n if (configMetadata) {\n this.logger.verbose(\n \"Found endpoint metadata in authority configuration\"\n );\n CacheHelpers.updateAuthorityEndpointMetadata(\n metadataEntity,\n configMetadata,\n false\n );\n return {\n source: AuthorityMetadataSource.CONFIG,\n };\n }\n\n this.logger.verbose(\n \"Did not find endpoint metadata in the config... Attempting to get endpoint metadata from the hardcoded values.\"\n );\n\n // skipAuthorityMetadataCache is used to bypass hardcoded authority metadata and force a network metadata cache lookup and network metadata request if no cached response is available.\n if (this.authorityOptions.skipAuthorityMetadataCache) {\n this.logger.verbose(\n \"Skipping hardcoded metadata cache since skipAuthorityMetadataCache is set to true. Attempting to get endpoint metadata from the network metadata cache.\"\n );\n } else {\n const hardcodedMetadata =\n this.getEndpointMetadataFromHardcodedValues();\n if (hardcodedMetadata) {\n CacheHelpers.updateAuthorityEndpointMetadata(\n metadataEntity,\n hardcodedMetadata,\n false\n );\n return {\n source: AuthorityMetadataSource.HARDCODED_VALUES,\n metadata: hardcodedMetadata,\n };\n } else {\n this.logger.verbose(\n \"Did not find endpoint metadata in hardcoded values... Attempting to get endpoint metadata from the network metadata cache.\"\n );\n }\n }\n\n // Check cached metadata entity expiration status\n const metadataEntityExpired =\n CacheHelpers.isAuthorityMetadataExpired(metadataEntity);\n if (\n this.isAuthoritySameType(metadataEntity) &&\n metadataEntity.endpointsFromNetwork &&\n !metadataEntityExpired\n ) {\n // No need to update\n this.logger.verbose(\"Found endpoint metadata in the cache.\");\n return { source: AuthorityMetadataSource.CACHE };\n } else if (metadataEntityExpired) {\n this.logger.verbose(\"The metadata entity is expired.\");\n }\n\n return null;\n }\n\n /**\n * Compares the number of url components after the domain to determine if the cached\n * authority metadata can be used for the requested authority. Protects against same domain different\n * authority such as login.microsoftonline.com/tenant and login.microsoftonline.com/tfp/tenant/policy\n * @param metadataEntity\n */\n private isAuthoritySameType(\n metadataEntity: AuthorityMetadataEntity\n ): boolean {\n const cachedAuthorityUrl = new UrlString(\n metadataEntity.canonical_authority\n );\n const cachedParts = cachedAuthorityUrl.getUrlComponents().PathSegments;\n\n return (\n cachedParts.length ===\n this.canonicalAuthorityUrlComponents.PathSegments.length\n );\n }\n\n /**\n * Parse authorityMetadata config option\n */\n private getEndpointMetadataFromConfig(): OpenIdConfigResponse | null {\n if (this.authorityOptions.authorityMetadata) {\n try {\n return JSON.parse(\n this.authorityOptions.authorityMetadata\n ) as OpenIdConfigResponse;\n } catch (e) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.invalidAuthorityMetadata\n );\n }\n }\n\n return null;\n }\n\n /**\n * Gets OAuth endpoints from the given OpenID configuration endpoint.\n *\n * @param hasHardcodedMetadata boolean\n */\n private async getEndpointMetadataFromNetwork(): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityGetEndpointMetadataFromNetwork,\n this.correlationId\n );\n\n const options: ImdsOptions = {};\n\n /*\n * TODO: Add a timeout if the authority exists in our library's\n * hardcoded list of metadata\n */\n\n const openIdConfigurationEndpoint =\n this.defaultOpenIdConfigurationEndpoint;\n this.logger.verbose(\n `Authority.getEndpointMetadataFromNetwork: attempting to retrieve OAuth endpoints from ${openIdConfigurationEndpoint}`\n );\n\n try {\n const response =\n await this.networkInterface.sendGetRequestAsync(\n openIdConfigurationEndpoint,\n options\n );\n const isValidResponse = isOpenIdConfigResponse(response.body);\n if (isValidResponse) {\n return response.body;\n } else {\n this.logger.verbose(\n `Authority.getEndpointMetadataFromNetwork: could not parse response as OpenID configuration`\n );\n return null;\n }\n } catch (e) {\n this.logger.verbose(\n `Authority.getEndpointMetadataFromNetwork: ${e}`\n );\n return null;\n }\n }\n\n /**\n * Get OAuth endpoints for common authorities.\n */\n private getEndpointMetadataFromHardcodedValues(): OpenIdConfigResponse | null {\n if (this.hostnameAndPort in EndpointMetadata) {\n return EndpointMetadata[this.hostnameAndPort];\n }\n\n return null;\n }\n\n /**\n * Update the retrieved metadata with regional information.\n * User selected Azure region will be used if configured.\n */\n private async updateMetadataWithRegionalInformation(\n metadata: OpenIdConfigResponse\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityUpdateMetadataWithRegionalInformation,\n this.correlationId\n );\n\n const userConfiguredAzureRegion =\n this.authorityOptions.azureRegionConfiguration?.azureRegion;\n\n if (userConfiguredAzureRegion) {\n if (\n userConfiguredAzureRegion !==\n Constants.AZURE_REGION_AUTO_DISCOVER_FLAG\n ) {\n this.regionDiscoveryMetadata.region_outcome =\n RegionDiscoveryOutcomes.CONFIGURED_NO_AUTO_DETECTION;\n this.regionDiscoveryMetadata.region_used =\n userConfiguredAzureRegion;\n return Authority.replaceWithRegionalInformation(\n metadata,\n userConfiguredAzureRegion\n );\n }\n\n const autodetectedRegionName = await invokeAsync(\n this.regionDiscovery.detectRegion.bind(this.regionDiscovery),\n PerformanceEvents.RegionDiscoveryDetectRegion,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(\n this.authorityOptions.azureRegionConfiguration\n ?.environmentRegion,\n this.regionDiscoveryMetadata\n );\n\n if (autodetectedRegionName) {\n this.regionDiscoveryMetadata.region_outcome =\n RegionDiscoveryOutcomes.AUTO_DETECTION_REQUESTED_SUCCESSFUL;\n this.regionDiscoveryMetadata.region_used =\n autodetectedRegionName;\n return Authority.replaceWithRegionalInformation(\n metadata,\n autodetectedRegionName\n );\n }\n\n this.regionDiscoveryMetadata.region_outcome =\n RegionDiscoveryOutcomes.AUTO_DETECTION_REQUESTED_FAILED;\n }\n\n return metadata;\n }\n\n /**\n * Updates the AuthorityMetadataEntity with new aliases, preferred_network and preferred_cache\n * and returns where the information was retrieved from\n * @param metadataEntity\n * @returns AuthorityMetadataSource\n */\n private async updateCloudDiscoveryMetadata(\n metadataEntity: AuthorityMetadataEntity\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityUpdateCloudDiscoveryMetadata,\n this.correlationId\n );\n const localMetadataSource =\n this.updateCloudDiscoveryMetadataFromLocalSources(metadataEntity);\n if (localMetadataSource) {\n return localMetadataSource;\n }\n\n // Fallback to network as metadata source\n const metadata = await invokeAsync(\n this.getCloudDiscoveryMetadataFromNetwork.bind(this),\n PerformanceEvents.AuthorityGetCloudDiscoveryMetadataFromNetwork,\n this.logger,\n this.performanceClient,\n this.correlationId\n )();\n\n if (metadata) {\n CacheHelpers.updateCloudDiscoveryMetadata(\n metadataEntity,\n metadata,\n true\n );\n return AuthorityMetadataSource.NETWORK;\n }\n\n // Metadata could not be obtained from the config, cache, network or hardcoded values\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.untrustedAuthority\n );\n }\n\n private updateCloudDiscoveryMetadataFromLocalSources(\n metadataEntity: AuthorityMetadataEntity\n ): AuthorityMetadataSource | null {\n this.logger.verbose(\n \"Attempting to get cloud discovery metadata from authority configuration\"\n );\n this.logger.verbosePii(\n `Known Authorities: ${\n this.authorityOptions.knownAuthorities ||\n Constants.NOT_APPLICABLE\n }`\n );\n this.logger.verbosePii(\n `Authority Metadata: ${\n this.authorityOptions.authorityMetadata ||\n Constants.NOT_APPLICABLE\n }`\n );\n this.logger.verbosePii(\n `Canonical Authority: ${\n metadataEntity.canonical_authority || Constants.NOT_APPLICABLE\n }`\n );\n const metadata = this.getCloudDiscoveryMetadataFromConfig();\n if (metadata) {\n this.logger.verbose(\n \"Found cloud discovery metadata in authority configuration\"\n );\n CacheHelpers.updateCloudDiscoveryMetadata(\n metadataEntity,\n metadata,\n false\n );\n return AuthorityMetadataSource.CONFIG;\n }\n\n // If the cached metadata came from config but that config was not passed to this instance, we must go to hardcoded values\n this.logger.verbose(\n \"Did not find cloud discovery metadata in the config... Attempting to get cloud discovery metadata from the hardcoded values.\"\n );\n\n if (this.options.skipAuthorityMetadataCache) {\n this.logger.verbose(\n \"Skipping hardcoded cloud discovery metadata cache since skipAuthorityMetadataCache is set to true. Attempting to get cloud discovery metadata from the network metadata cache.\"\n );\n } else {\n const hardcodedMetadata =\n getCloudDiscoveryMetadataFromHardcodedValues(\n this.hostnameAndPort\n );\n if (hardcodedMetadata) {\n this.logger.verbose(\n \"Found cloud discovery metadata from hardcoded values.\"\n );\n CacheHelpers.updateCloudDiscoveryMetadata(\n metadataEntity,\n hardcodedMetadata,\n false\n );\n return AuthorityMetadataSource.HARDCODED_VALUES;\n }\n\n this.logger.verbose(\n \"Did not find cloud discovery metadata in hardcoded values... Attempting to get cloud discovery metadata from the network metadata cache.\"\n );\n }\n\n const metadataEntityExpired =\n CacheHelpers.isAuthorityMetadataExpired(metadataEntity);\n if (\n this.isAuthoritySameType(metadataEntity) &&\n metadataEntity.aliasesFromNetwork &&\n !metadataEntityExpired\n ) {\n this.logger.verbose(\"Found cloud discovery metadata in the cache.\");\n // No need to update\n return AuthorityMetadataSource.CACHE;\n } else if (metadataEntityExpired) {\n this.logger.verbose(\"The metadata entity is expired.\");\n }\n\n return null;\n }\n\n /**\n * Parse cloudDiscoveryMetadata config or check knownAuthorities\n */\n private getCloudDiscoveryMetadataFromConfig(): CloudDiscoveryMetadata | null {\n // CIAM does not support cloud discovery metadata\n if (this.authorityType === AuthorityType.Ciam) {\n this.logger.verbose(\n \"CIAM authorities do not support cloud discovery metadata, generate the aliases from authority host.\"\n );\n return Authority.createCloudDiscoveryMetadataFromHost(\n this.hostnameAndPort\n );\n }\n\n // Check if network response was provided in config\n if (this.authorityOptions.cloudDiscoveryMetadata) {\n this.logger.verbose(\n \"The cloud discovery metadata has been provided as a network response, in the config.\"\n );\n try {\n this.logger.verbose(\n \"Attempting to parse the cloud discovery metadata.\"\n );\n const parsedResponse = JSON.parse(\n this.authorityOptions.cloudDiscoveryMetadata\n ) as CloudInstanceDiscoveryResponse;\n const metadata = getCloudDiscoveryMetadataFromNetworkResponse(\n parsedResponse.metadata,\n this.hostnameAndPort\n );\n this.logger.verbose(\"Parsed the cloud discovery metadata.\");\n if (metadata) {\n this.logger.verbose(\n \"There is returnable metadata attached to the parsed cloud discovery metadata.\"\n );\n return metadata;\n } else {\n this.logger.verbose(\n \"There is no metadata attached to the parsed cloud discovery metadata.\"\n );\n }\n } catch (e) {\n this.logger.verbose(\n \"Unable to parse the cloud discovery metadata. Throwing Invalid Cloud Discovery Metadata Error.\"\n );\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.invalidCloudDiscoveryMetadata\n );\n }\n }\n\n // If cloudDiscoveryMetadata is empty or does not contain the host, check knownAuthorities\n if (this.isInKnownAuthorities()) {\n this.logger.verbose(\n \"The host is included in knownAuthorities. Creating new cloud discovery metadata from the host.\"\n );\n return Authority.createCloudDiscoveryMetadataFromHost(\n this.hostnameAndPort\n );\n }\n\n return null;\n }\n\n /**\n * Called to get metadata from network if CloudDiscoveryMetadata was not populated by config\n *\n * @param hasHardcodedMetadata boolean\n */\n private async getCloudDiscoveryMetadataFromNetwork(): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityGetCloudDiscoveryMetadataFromNetwork,\n this.correlationId\n );\n const instanceDiscoveryEndpoint = `${Constants.AAD_INSTANCE_DISCOVERY_ENDPT}${this.canonicalAuthority}oauth2/v2.0/authorize`;\n const options: ImdsOptions = {};\n\n /*\n * TODO: Add a timeout if the authority exists in our library's\n * hardcoded list of metadata\n */\n\n let match = null;\n try {\n const response = await this.networkInterface.sendGetRequestAsync<\n | CloudInstanceDiscoveryResponse\n | CloudInstanceDiscoveryErrorResponse\n >(instanceDiscoveryEndpoint, options);\n let typedResponseBody:\n | CloudInstanceDiscoveryResponse\n | CloudInstanceDiscoveryErrorResponse;\n let metadata: Array;\n if (isCloudInstanceDiscoveryResponse(response.body)) {\n typedResponseBody =\n response.body as CloudInstanceDiscoveryResponse;\n metadata = typedResponseBody.metadata;\n\n this.logger.verbosePii(\n `tenant_discovery_endpoint is: ${typedResponseBody.tenant_discovery_endpoint}`\n );\n } else if (isCloudInstanceDiscoveryErrorResponse(response.body)) {\n this.logger.warning(\n `A CloudInstanceDiscoveryErrorResponse was returned. The cloud instance discovery network request's status code is: ${response.status}`\n );\n\n typedResponseBody =\n response.body as CloudInstanceDiscoveryErrorResponse;\n if (typedResponseBody.error === Constants.INVALID_INSTANCE) {\n this.logger.error(\n \"The CloudInstanceDiscoveryErrorResponse error is invalid_instance.\"\n );\n return null;\n }\n\n this.logger.warning(\n `The CloudInstanceDiscoveryErrorResponse error is ${typedResponseBody.error}`\n );\n this.logger.warning(\n `The CloudInstanceDiscoveryErrorResponse error description is ${typedResponseBody.error_description}`\n );\n\n this.logger.warning(\n \"Setting the value of the CloudInstanceDiscoveryMetadata (returned from the network) to []\"\n );\n metadata = [];\n } else {\n this.logger.error(\n \"AAD did not return a CloudInstanceDiscoveryResponse or CloudInstanceDiscoveryErrorResponse\"\n );\n return null;\n }\n\n this.logger.verbose(\n \"Attempting to find a match between the developer's authority and the CloudInstanceDiscoveryMetadata returned from the network request.\"\n );\n match = getCloudDiscoveryMetadataFromNetworkResponse(\n metadata,\n this.hostnameAndPort\n );\n } catch (error) {\n if (error instanceof AuthError) {\n this.logger.error(\n `There was a network error while attempting to get the cloud discovery instance metadata.\\nError: ${error.errorCode}\\nError Description: ${error.errorMessage}`\n );\n } else {\n const typedError = error as Error;\n this.logger.error(\n `A non-MSALJS error was thrown while attempting to get the cloud instance discovery metadata.\\nError: ${typedError.name}\\nError Description: ${typedError.message}`\n );\n }\n\n return null;\n }\n\n // Custom Domain scenario, host is trusted because Instance Discovery call succeeded\n if (!match) {\n this.logger.warning(\n \"The developer's authority was not found within the CloudInstanceDiscoveryMetadata returned from the network request.\"\n );\n this.logger.verbose(\n \"Creating custom Authority for custom domain scenario.\"\n );\n\n match = Authority.createCloudDiscoveryMetadataFromHost(\n this.hostnameAndPort\n );\n }\n return match;\n }\n\n /**\n * Helper function to determine if this host is included in the knownAuthorities config option\n */\n private isInKnownAuthorities(): boolean {\n const matches = this.authorityOptions.knownAuthorities.filter(\n (authority) => {\n return (\n authority &&\n UrlString.getDomainFromUrl(authority).toLowerCase() ===\n this.hostnameAndPort\n );\n }\n );\n return matches.length > 0;\n }\n\n /**\n * helper function to populate the authority based on azureCloudOptions\n * @param authorityString\n * @param azureCloudOptions\n */\n static generateAuthority(\n authorityString: string,\n azureCloudOptions?: AzureCloudOptions\n ): string {\n let authorityAzureCloudInstance;\n\n if (\n azureCloudOptions &&\n azureCloudOptions.azureCloudInstance !== AzureCloudInstance.None\n ) {\n const tenant = azureCloudOptions.tenant\n ? azureCloudOptions.tenant\n : Constants.DEFAULT_COMMON_TENANT;\n authorityAzureCloudInstance = `${azureCloudOptions.azureCloudInstance}/${tenant}/`;\n }\n\n return authorityAzureCloudInstance\n ? authorityAzureCloudInstance\n : authorityString;\n }\n\n /**\n * Creates cloud discovery metadata object from a given host\n * @param host\n */\n static createCloudDiscoveryMetadataFromHost(\n host: string\n ): CloudDiscoveryMetadata {\n return {\n preferred_network: host,\n preferred_cache: host,\n aliases: [host],\n };\n }\n\n /**\n * helper function to generate environment from authority object\n */\n getPreferredCache(): string {\n if (this.discoveryComplete()) {\n return this.metadata.preferred_cache;\n } else {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n }\n\n /**\n * Returns whether or not the provided host is an alias of this authority instance\n * @param host\n */\n isAlias(host: string): boolean {\n return this.metadata.aliases.indexOf(host) > -1;\n }\n\n /**\n * Returns whether or not the provided host is an alias of a known Microsoft authority for purposes of endpoint discovery\n * @param host\n */\n isAliasOfKnownMicrosoftAuthority(host: string): boolean {\n return InstanceDiscoveryMetadataAliases.has(host);\n }\n\n /**\n * Checks whether the provided host is that of a public cloud authority\n *\n * @param authority string\n * @returns bool\n */\n static isPublicCloudAuthority(host: string): boolean {\n return Constants.KNOWN_PUBLIC_CLOUDS.indexOf(host) >= 0;\n }\n\n /**\n * Rebuild the authority string with the region\n *\n * @param host string\n * @param region string\n */\n static buildRegionalAuthorityString(\n host: string,\n region: string,\n queryString?: string\n ): string {\n // Create and validate a Url string object with the initial authority string\n const authorityUrlInstance = new UrlString(host);\n authorityUrlInstance.validateAsUri();\n\n const authorityUrlParts = authorityUrlInstance.getUrlComponents();\n\n let hostNameAndPort = `${region}.${authorityUrlParts.HostNameAndPort}`;\n\n if (this.isPublicCloudAuthority(authorityUrlParts.HostNameAndPort)) {\n hostNameAndPort = `${region}.${Constants.REGIONAL_AUTH_PUBLIC_CLOUD_SUFFIX}`;\n }\n\n // Include the query string portion of the url\n const url = UrlString.constructAuthorityUriFromObject({\n ...authorityUrlInstance.getUrlComponents(),\n HostNameAndPort: hostNameAndPort,\n }).urlString;\n\n // Add the query string if a query string was provided\n if (queryString) return `${url}?${queryString}`;\n\n return url;\n }\n\n /**\n * Replace the endpoints in the metadata object with their regional equivalents.\n *\n * @param metadata OpenIdConfigResponse\n * @param azureRegion string\n */\n static replaceWithRegionalInformation(\n metadata: OpenIdConfigResponse,\n azureRegion: string\n ): OpenIdConfigResponse {\n const regionalMetadata = { ...metadata };\n regionalMetadata.authorization_endpoint =\n Authority.buildRegionalAuthorityString(\n regionalMetadata.authorization_endpoint,\n azureRegion\n );\n\n regionalMetadata.token_endpoint =\n Authority.buildRegionalAuthorityString(\n regionalMetadata.token_endpoint,\n azureRegion\n );\n\n if (regionalMetadata.end_session_endpoint) {\n regionalMetadata.end_session_endpoint =\n Authority.buildRegionalAuthorityString(\n regionalMetadata.end_session_endpoint,\n azureRegion\n );\n }\n\n return regionalMetadata;\n }\n\n /**\n * Transform CIAM_AUTHORIY as per the below rules:\n * If no path segments found and it is a CIAM authority (hostname ends with .ciamlogin.com), then transform it\n *\n * NOTE: The transformation path should go away once STS supports CIAM with the format: `tenantIdorDomain.ciamlogin.com`\n * `ciamlogin.com` can also change in the future and we should accommodate the same\n *\n * @param authority\n */\n static transformCIAMAuthority(authority: string): string {\n let ciamAuthority = authority;\n const authorityUrl = new UrlString(authority);\n const authorityUrlComponents = authorityUrl.getUrlComponents();\n\n // check if transformation is needed\n if (\n authorityUrlComponents.PathSegments.length === 0 &&\n authorityUrlComponents.HostNameAndPort.endsWith(\n Constants.CIAM_AUTH_URL\n )\n ) {\n const tenantIdOrDomain =\n authorityUrlComponents.HostNameAndPort.split(\".\")[0];\n ciamAuthority = `${ciamAuthority}${tenantIdOrDomain}${Constants.AAD_TENANT_DOMAIN_SUFFIX}`;\n }\n\n return ciamAuthority;\n }\n}\n\n/**\n * Extract tenantId from authority\n */\nexport function getTenantFromAuthorityString(\n authority: string\n): string | undefined {\n const authorityUrl = new UrlString(authority);\n const authorityUrlComponents = authorityUrl.getUrlComponents();\n /**\n * For credential matching purposes, tenantId is the last path segment of the authority URL:\n * AAD Authority - domain/tenantId -> Credentials are cached with realm = tenantId\n * B2C Authority - domain/{tenantId}?/.../policy -> Credentials are cached with realm = policy\n * tenantId is downcased because B2C policies can have mixed case but tfp claim is downcased\n *\n * Note that we may not have any path segments in certain OIDC scenarios.\n */\n const tenantId =\n authorityUrlComponents.PathSegments.slice(-1)[0]?.toLowerCase();\n\n switch (tenantId) {\n case AADAuthorityConstants.COMMON:\n case AADAuthorityConstants.ORGANIZATIONS:\n case AADAuthorityConstants.CONSUMERS:\n return undefined;\n default:\n return tenantId;\n }\n}\n\nexport function formatAuthorityUri(authorityUri: string): string {\n return authorityUri.endsWith(Constants.FORWARD_SLASH)\n ? authorityUri\n : `${authorityUri}${Constants.FORWARD_SLASH}`;\n}\n\nexport function buildStaticAuthorityOptions(\n authOptions: Partial\n): StaticAuthorityOptions {\n const rawCloudDiscoveryMetadata = authOptions.cloudDiscoveryMetadata;\n let cloudDiscoveryMetadata: CloudInstanceDiscoveryResponse | undefined =\n undefined;\n if (rawCloudDiscoveryMetadata) {\n try {\n cloudDiscoveryMetadata = JSON.parse(rawCloudDiscoveryMetadata);\n } catch (e) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.invalidCloudDiscoveryMetadata\n );\n }\n }\n return {\n canonicalAuthority: authOptions.authority\n ? formatAuthorityUri(authOptions.authority)\n : undefined,\n knownAuthorities: authOptions.knownAuthorities,\n cloudDiscoveryMetadata: cloudDiscoveryMetadata,\n };\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { Constants } from \"./Constants\";\nimport { ICrypto } from \"../crypto/ICrypto\";\nimport {\n ClientAuthErrorCodes,\n createClientAuthError,\n} from \"../error/ClientAuthError\";\n\n/**\n * Type which defines the object that is stringified, encoded and sent in the state value.\n * Contains the following:\n * - id - unique identifier for this request\n * - ts - timestamp for the time the request was made. Used to ensure that token expiration is not calculated incorrectly.\n * - platformState - string value sent from the platform.\n */\nexport type LibraryStateObject = {\n id: string;\n meta?: Record;\n};\n\n/**\n * Type which defines the stringified and encoded object sent to the service in the authorize request.\n */\nexport type RequestStateObject = {\n userRequestState: string;\n libraryState: LibraryStateObject;\n};\n\n/**\n * Class which provides helpers for OAuth 2.0 protocol specific values\n */\nexport class ProtocolUtils {\n /**\n * Appends user state with random guid, or returns random guid.\n * @param userState\n * @param randomGuid\n */\n static setRequestState(\n cryptoObj: ICrypto,\n userState?: string,\n meta?: Record\n ): string {\n const libraryState = ProtocolUtils.generateLibraryState(\n cryptoObj,\n meta\n );\n return userState\n ? `${libraryState}${Constants.RESOURCE_DELIM}${userState}`\n : libraryState;\n }\n\n /**\n * Generates the state value used by the common library.\n * @param randomGuid\n * @param cryptoObj\n */\n static generateLibraryState(\n cryptoObj: ICrypto,\n meta?: Record\n ): string {\n if (!cryptoObj) {\n throw createClientAuthError(ClientAuthErrorCodes.noCryptoObject);\n }\n\n // Create a state object containing a unique id and the timestamp of the request creation\n const stateObj: LibraryStateObject = {\n id: cryptoObj.createNewGuid(),\n };\n\n if (meta) {\n stateObj.meta = meta;\n }\n\n const stateString = JSON.stringify(stateObj);\n\n return cryptoObj.base64Encode(stateString);\n }\n\n /**\n * Parses the state into the RequestStateObject, which contains the LibraryState info and the state passed by the user.\n * @param state\n * @param cryptoObj\n */\n static parseRequestState(\n cryptoObj: ICrypto,\n state: string\n ): RequestStateObject {\n if (!cryptoObj) {\n throw createClientAuthError(ClientAuthErrorCodes.noCryptoObject);\n }\n\n if (!state) {\n throw createClientAuthError(ClientAuthErrorCodes.invalidState);\n }\n\n try {\n // Split the state between library state and user passed state and decode them separately\n const splitState = state.split(Constants.RESOURCE_DELIM);\n const libraryState = splitState[0];\n const userState =\n splitState.length > 1\n ? splitState.slice(1).join(Constants.RESOURCE_DELIM)\n : Constants.EMPTY_STRING;\n const libraryStateString = cryptoObj.base64Decode(libraryState);\n const libraryStateObj = JSON.parse(\n libraryStateString\n ) as LibraryStateObject;\n return {\n userRequestState: userState || Constants.EMPTY_STRING,\n libraryState: libraryStateObj,\n };\n } catch (e) {\n throw createClientAuthError(ClientAuthErrorCodes.invalidState);\n }\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type CcsCredential = {\n credential: string;\n type: CcsCredentialType;\n};\n\nexport const CcsCredentialType = {\n HOME_ACCOUNT_ID: \"home_account_id\",\n UPN: \"UPN\",\n} as const;\nexport type CcsCredentialType =\n (typeof CcsCredentialType)[keyof typeof CcsCredentialType];\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IdTokenEntity } from \"./IdTokenEntity\";\nimport { AccessTokenEntity } from \"./AccessTokenEntity\";\nimport { RefreshTokenEntity } from \"./RefreshTokenEntity\";\nimport { AccountEntity } from \"./AccountEntity\";\nimport { AppMetadataEntity } from \"./AppMetadataEntity\";\n\n/** @internal */\nexport class CacheRecord {\n account: AccountEntity | null;\n idToken: IdTokenEntity | null;\n accessToken: AccessTokenEntity | null;\n refreshToken: RefreshTokenEntity | null;\n appMetadata: AppMetadataEntity | null;\n\n constructor(\n accountEntity?: AccountEntity | null,\n idTokenEntity?: IdTokenEntity | null,\n accessTokenEntity?: AccessTokenEntity | null,\n refreshTokenEntity?: RefreshTokenEntity | null,\n appMetadataEntity?: AppMetadataEntity | null\n ) {\n this.account = accountEntity || null;\n this.idToken = idTokenEntity || null;\n this.accessToken = accessTokenEntity || null;\n this.refreshToken = refreshTokenEntity || null;\n this.appMetadata = appMetadataEntity || null;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n BrowserConfigurationAuthErrorCodes,\n createBrowserConfigurationAuthError,\n} from \"../error/BrowserConfigurationAuthError\";\nimport { BrowserCacheLocation } from \"../utils/BrowserConstants\";\nimport { IWindowStorage } from \"./IWindowStorage\";\n\nexport class BrowserStorage implements IWindowStorage {\n private windowStorage: Storage;\n\n constructor(cacheLocation: string) {\n this.validateWindowStorage(cacheLocation);\n this.windowStorage = window[cacheLocation];\n }\n\n private validateWindowStorage(cacheLocation: string): void {\n if (\n (cacheLocation !== BrowserCacheLocation.LocalStorage &&\n cacheLocation !== BrowserCacheLocation.SessionStorage) ||\n !window[cacheLocation]\n ) {\n throw createBrowserConfigurationAuthError(\n BrowserConfigurationAuthErrorCodes.storageNotSupported\n );\n }\n }\n\n getItem(key: string): string | null {\n return this.windowStorage.getItem(key);\n }\n\n setItem(key: string, value: string): void {\n this.windowStorage.setItem(key, value);\n }\n\n removeItem(key: string): void {\n this.windowStorage.removeItem(key);\n }\n\n getKeys(): string[] {\n return Object.keys(this.windowStorage);\n }\n\n containsKey(key: string): boolean {\n return this.windowStorage.hasOwnProperty(key);\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { InteractionType } from \"./BrowserConstants\";\nimport {\n ICrypto,\n RequestStateObject,\n ProtocolUtils,\n createClientAuthError,\n ClientAuthErrorCodes,\n} from \"@azure/msal-common\";\n\nexport type BrowserStateObject = {\n interactionType: InteractionType;\n};\n\n/**\n * Extracts the BrowserStateObject from the state string.\n * @param browserCrypto\n * @param state\n */\nexport function extractBrowserRequestState(\n browserCrypto: ICrypto,\n state: string\n): BrowserStateObject | null {\n if (!state) {\n return null;\n }\n\n try {\n const requestStateObj: RequestStateObject =\n ProtocolUtils.parseRequestState(browserCrypto, state);\n return requestStateObj.libraryState.meta as BrowserStateObject;\n } catch (e) {\n throw createClientAuthError(ClientAuthErrorCodes.invalidState);\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n Constants,\n PersistentCacheKeys,\n StringUtils,\n CommonAuthorizationCodeRequest,\n ICrypto,\n AccountEntity,\n IdTokenEntity,\n AccessTokenEntity,\n RefreshTokenEntity,\n AppMetadataEntity,\n CacheManager,\n ServerTelemetryEntity,\n ThrottlingEntity,\n ProtocolUtils,\n Logger,\n AuthorityMetadataEntity,\n DEFAULT_CRYPTO_IMPLEMENTATION,\n AccountInfo,\n ActiveAccountFilters,\n CcsCredential,\n CcsCredentialType,\n AuthToken,\n ValidCredentialType,\n TokenKeys,\n CredentialType,\n CacheRecord,\n AuthenticationScheme,\n createClientAuthError,\n ClientAuthErrorCodes,\n PerformanceEvents,\n IPerformanceClient,\n StaticAuthorityOptions,\n CacheHelpers,\n} from \"@azure/msal-common\";\nimport { CacheOptions } from \"../config/Configuration\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../error/BrowserAuthError\";\nimport {\n BrowserCacheLocation,\n InteractionType,\n TemporaryCacheKeys,\n InMemoryCacheKeys,\n StaticCacheKeys,\n} from \"../utils/BrowserConstants\";\nimport { BrowserStorage } from \"./BrowserStorage\";\nimport { MemoryStorage } from \"./MemoryStorage\";\nimport { IWindowStorage } from \"./IWindowStorage\";\nimport { extractBrowserRequestState } from \"../utils/BrowserProtocolUtils\";\nimport { NativeTokenRequest } from \"../broker/nativeBroker/NativeRequest\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport { SilentRequest } from \"../request/SilentRequest\";\nimport { SsoSilentRequest } from \"../request/SsoSilentRequest\";\nimport { RedirectRequest } from \"../request/RedirectRequest\";\nimport { PopupRequest } from \"../request/PopupRequest\";\nimport { base64Decode } from \"../encode/Base64Decode\";\nimport { base64Encode } from \"../encode/Base64Encode\";\n\n/**\n * This class implements the cache storage interface for MSAL through browser local or session storage.\n * Cookies are only used if storeAuthStateInCookie is true, and are only used for\n * parameters such as state and nonce, generally.\n */\nexport class BrowserCacheManager extends CacheManager {\n // Cache configuration, either set by user or default values.\n protected cacheConfig: Required;\n // Window storage object (either local or sessionStorage)\n protected browserStorage: IWindowStorage;\n // Internal in-memory storage object used for data used by msal that does not need to persist across page loads\n protected internalStorage: MemoryStorage;\n // Temporary cache\n protected temporaryCacheStorage: IWindowStorage;\n // Logger instance\n protected logger: Logger;\n\n // Cookie life calculation (hours * minutes * seconds * ms)\n protected readonly COOKIE_LIFE_MULTIPLIER = 24 * 60 * 60 * 1000;\n\n constructor(\n clientId: string,\n cacheConfig: Required,\n cryptoImpl: ICrypto,\n logger: Logger,\n staticAuthorityOptions?: StaticAuthorityOptions\n ) {\n super(clientId, cryptoImpl, logger, staticAuthorityOptions);\n this.cacheConfig = cacheConfig;\n this.logger = logger;\n this.internalStorage = new MemoryStorage();\n this.browserStorage = this.setupBrowserStorage(\n this.cacheConfig.cacheLocation\n );\n this.temporaryCacheStorage = this.setupTemporaryCacheStorage(\n this.cacheConfig.temporaryCacheLocation,\n this.cacheConfig.cacheLocation\n );\n\n // Migrate cache entries from older versions of MSAL.\n if (cacheConfig.cacheMigrationEnabled) {\n this.migrateCacheEntries();\n this.createKeyMaps();\n }\n }\n\n /**\n * Returns a window storage class implementing the IWindowStorage interface that corresponds to the configured cacheLocation.\n * @param cacheLocation\n */\n protected setupBrowserStorage(\n cacheLocation: BrowserCacheLocation | string\n ): IWindowStorage {\n switch (cacheLocation) {\n case BrowserCacheLocation.LocalStorage:\n case BrowserCacheLocation.SessionStorage:\n try {\n return new BrowserStorage(cacheLocation);\n } catch (e) {\n this.logger.verbose(e as string);\n break;\n }\n case BrowserCacheLocation.MemoryStorage:\n default:\n break;\n }\n this.cacheConfig.cacheLocation = BrowserCacheLocation.MemoryStorage;\n return new MemoryStorage();\n }\n\n /**\n * Returns a window storage class implementing the IWindowStorage interface that corresponds to the configured temporaryCacheLocation.\n * @param temporaryCacheLocation\n * @param cacheLocation\n */\n protected setupTemporaryCacheStorage(\n temporaryCacheLocation: BrowserCacheLocation | string,\n cacheLocation: BrowserCacheLocation | string\n ): IWindowStorage {\n switch (cacheLocation) {\n case BrowserCacheLocation.LocalStorage:\n case BrowserCacheLocation.SessionStorage:\n try {\n // Temporary cache items will always be stored in session storage to mitigate problems caused by multiple tabs\n return new BrowserStorage(\n temporaryCacheLocation ||\n BrowserCacheLocation.SessionStorage\n );\n } catch (e) {\n this.logger.verbose(e as string);\n return this.internalStorage;\n }\n case BrowserCacheLocation.MemoryStorage:\n default:\n return this.internalStorage;\n }\n }\n\n /**\n * Migrate all old cache entries to new schema. No rollback supported.\n * @param storeAuthStateInCookie\n */\n protected migrateCacheEntries(): void {\n const idTokenKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.ID_TOKEN}`;\n const clientInfoKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.CLIENT_INFO}`;\n const errorKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.ERROR}`;\n const errorDescKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.ERROR_DESC}`;\n\n const idTokenValue = this.browserStorage.getItem(idTokenKey);\n const clientInfoValue = this.browserStorage.getItem(clientInfoKey);\n const errorValue = this.browserStorage.getItem(errorKey);\n const errorDescValue = this.browserStorage.getItem(errorDescKey);\n\n const values = [\n idTokenValue,\n clientInfoValue,\n errorValue,\n errorDescValue,\n ];\n const keysToMigrate = [\n PersistentCacheKeys.ID_TOKEN,\n PersistentCacheKeys.CLIENT_INFO,\n PersistentCacheKeys.ERROR,\n PersistentCacheKeys.ERROR_DESC,\n ];\n\n keysToMigrate.forEach((cacheKey: string, index: number) =>\n this.migrateCacheEntry(cacheKey, values[index])\n );\n }\n\n /**\n * Utility function to help with migration.\n * @param newKey\n * @param value\n * @param storeAuthStateInCookie\n */\n protected migrateCacheEntry(newKey: string, value: string | null): void {\n if (value) {\n this.setTemporaryCache(newKey, value, true);\n }\n }\n\n /**\n * Searches all cache entries for MSAL accounts and creates the account key map\n * This is used to migrate users from older versions of MSAL which did not create the map.\n * @returns\n */\n private createKeyMaps(): void {\n this.logger.trace(\"BrowserCacheManager - createKeyMaps called.\");\n const accountKeys = this.getItem(StaticCacheKeys.ACCOUNT_KEYS);\n const tokenKeys = this.getItem(\n `${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`\n );\n if (accountKeys && tokenKeys) {\n this.logger.verbose(\n \"BrowserCacheManager:createKeyMaps - account and token key maps already exist, skipping migration.\"\n );\n // Key maps already exist, no need to iterate through cache\n return;\n }\n\n const allKeys = this.browserStorage.getKeys();\n allKeys.forEach((key) => {\n if (this.isCredentialKey(key)) {\n // Get item, parse, validate and write key to map\n const value = this.getItem(key);\n if (value) {\n const credObj = this.validateAndParseJson(value);\n if (credObj && credObj.hasOwnProperty(\"credentialType\")) {\n switch (credObj[\"credentialType\"]) {\n case CredentialType.ID_TOKEN:\n if (CacheHelpers.isIdTokenEntity(credObj)) {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - idToken found, saving key to token key map\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - idToken with key: ${key} found, saving key to token key map`\n );\n const idTokenEntity =\n credObj as IdTokenEntity;\n const newKey =\n this.updateCredentialCacheKey(\n key,\n idTokenEntity\n );\n this.addTokenKey(\n newKey,\n CredentialType.ID_TOKEN\n );\n return;\n } else {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - key found matching idToken schema with value containing idToken credentialType field but value failed IdTokenEntity validation, skipping.\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - failed idToken validation on key: ${key}`\n );\n }\n break;\n case CredentialType.ACCESS_TOKEN:\n case CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME:\n if (CacheHelpers.isAccessTokenEntity(credObj)) {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - accessToken found, saving key to token key map\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - accessToken with key: ${key} found, saving key to token key map`\n );\n const accessTokenEntity =\n credObj as AccessTokenEntity;\n const newKey =\n this.updateCredentialCacheKey(\n key,\n accessTokenEntity\n );\n this.addTokenKey(\n newKey,\n CredentialType.ACCESS_TOKEN\n );\n return;\n } else {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - key found matching accessToken schema with value containing accessToken credentialType field but value failed AccessTokenEntity validation, skipping.\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - failed accessToken validation on key: ${key}`\n );\n }\n break;\n case CredentialType.REFRESH_TOKEN:\n if (\n CacheHelpers.isRefreshTokenEntity(credObj)\n ) {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - refreshToken found, saving key to token key map\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - refreshToken with key: ${key} found, saving key to token key map`\n );\n const refreshTokenEntity =\n credObj as RefreshTokenEntity;\n const newKey =\n this.updateCredentialCacheKey(\n key,\n refreshTokenEntity\n );\n this.addTokenKey(\n newKey,\n CredentialType.REFRESH_TOKEN\n );\n return;\n } else {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - key found matching refreshToken schema with value containing refreshToken credentialType field but value failed RefreshTokenEntity validation, skipping.\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - failed refreshToken validation on key: ${key}`\n );\n }\n break;\n default:\n // If credentialType isn't one of our predefined ones, it may not be an MSAL cache value. Ignore.\n }\n }\n }\n }\n\n if (this.isAccountKey(key)) {\n const value = this.getItem(key);\n if (value) {\n const accountObj = this.validateAndParseJson(value);\n if (\n accountObj &&\n AccountEntity.isAccountEntity(accountObj)\n ) {\n this.logger.trace(\n \"BrowserCacheManager:createKeyMaps - account found, saving key to account key map\"\n );\n this.logger.tracePii(\n `BrowserCacheManager:createKeyMaps - account with key: ${key} found, saving key to account key map`\n );\n this.addAccountKeyToMap(key);\n }\n }\n }\n });\n }\n\n /**\n * Parses passed value as JSON object, JSON.parse() will throw an error.\n * @param input\n */\n protected validateAndParseJson(jsonValue: string): object | null {\n try {\n const parsedJson = JSON.parse(jsonValue);\n /**\n * There are edge cases in which JSON.parse will successfully parse a non-valid JSON object\n * (e.g. JSON.parse will parse an escaped string into an unescaped string), so adding a type check\n * of the parsed value is necessary in order to be certain that the string represents a valid JSON object.\n *\n */\n return parsedJson && typeof parsedJson === \"object\"\n ? parsedJson\n : null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * fetches the entry from the browser storage based off the key\n * @param key\n */\n getItem(key: string): string | null {\n return this.browserStorage.getItem(key);\n }\n\n /**\n * sets the entry in the browser storage\n * @param key\n * @param value\n */\n setItem(key: string, value: string): void {\n this.browserStorage.setItem(key, value);\n }\n\n /**\n * fetch the account entity from the platform cache\n * @param accountKey\n */\n getAccount(accountKey: string, logger?: Logger): AccountEntity | null {\n this.logger.trace(\"BrowserCacheManager.getAccount called\");\n const accountEntity = this.getCachedAccountEntity(accountKey);\n\n return this.updateOutdatedCachedAccount(\n accountKey,\n accountEntity,\n logger\n );\n }\n\n /**\n * Reads account from cache, deserializes it into an account entity and returns it.\n * If account is not found from the key, returns null and removes key from map.\n * @param accountKey\n * @returns\n */\n getCachedAccountEntity(accountKey: string): AccountEntity | null {\n const serializedAccount = this.getItem(accountKey);\n if (!serializedAccount) {\n this.removeAccountKeyFromMap(accountKey);\n return null;\n }\n\n const parsedAccount = this.validateAndParseJson(serializedAccount);\n if (!parsedAccount || !AccountEntity.isAccountEntity(parsedAccount)) {\n this.removeAccountKeyFromMap(accountKey);\n return null;\n }\n\n return CacheManager.toObject(\n new AccountEntity(),\n parsedAccount\n );\n }\n\n /**\n * set account entity in the platform cache\n * @param account\n */\n setAccount(account: AccountEntity): void {\n this.logger.trace(\"BrowserCacheManager.setAccount called\");\n const key = account.generateAccountKey();\n this.setItem(key, JSON.stringify(account));\n this.addAccountKeyToMap(key);\n }\n\n /**\n * Returns the array of account keys currently cached\n * @returns\n */\n getAccountKeys(): Array {\n this.logger.trace(\"BrowserCacheManager.getAccountKeys called\");\n const accountKeys = this.getItem(StaticCacheKeys.ACCOUNT_KEYS);\n if (accountKeys) {\n return JSON.parse(accountKeys);\n }\n\n this.logger.verbose(\n \"BrowserCacheManager.getAccountKeys - No account keys found\"\n );\n return [];\n }\n\n /**\n * Add a new account to the key map\n * @param key\n */\n addAccountKeyToMap(key: string): void {\n this.logger.trace(\"BrowserCacheManager.addAccountKeyToMap called\");\n this.logger.tracePii(\n `BrowserCacheManager.addAccountKeyToMap called with key: ${key}`\n );\n const accountKeys = this.getAccountKeys();\n if (accountKeys.indexOf(key) === -1) {\n // Only add key if it does not already exist in the map\n accountKeys.push(key);\n this.setItem(\n StaticCacheKeys.ACCOUNT_KEYS,\n JSON.stringify(accountKeys)\n );\n this.logger.verbose(\n \"BrowserCacheManager.addAccountKeyToMap account key added\"\n );\n } else {\n this.logger.verbose(\n \"BrowserCacheManager.addAccountKeyToMap account key already exists in map\"\n );\n }\n }\n\n /**\n * Remove an account from the key map\n * @param key\n */\n removeAccountKeyFromMap(key: string): void {\n this.logger.trace(\"BrowserCacheManager.removeAccountKeyFromMap called\");\n this.logger.tracePii(\n `BrowserCacheManager.removeAccountKeyFromMap called with key: ${key}`\n );\n const accountKeys = this.getAccountKeys();\n const removalIndex = accountKeys.indexOf(key);\n if (removalIndex > -1) {\n accountKeys.splice(removalIndex, 1);\n this.setItem(\n StaticCacheKeys.ACCOUNT_KEYS,\n JSON.stringify(accountKeys)\n );\n this.logger.trace(\n \"BrowserCacheManager.removeAccountKeyFromMap account key removed\"\n );\n } else {\n this.logger.trace(\n \"BrowserCacheManager.removeAccountKeyFromMap key not found in existing map\"\n );\n }\n }\n\n /**\n * Extends inherited removeAccount function to include removal of the account key from the map\n * @param key\n */\n async removeAccount(key: string): Promise {\n void super.removeAccount(key);\n this.removeAccountKeyFromMap(key);\n }\n\n /**\n * Remove account entity from the platform cache if it's outdated\n * @param accountKey\n */\n removeOutdatedAccount(accountKey: string): void {\n this.removeItem(accountKey);\n this.removeAccountKeyFromMap(accountKey);\n }\n\n /**\n * Removes given idToken from the cache and from the key map\n * @param key\n */\n removeIdToken(key: string): void {\n super.removeIdToken(key);\n this.removeTokenKey(key, CredentialType.ID_TOKEN);\n }\n\n /**\n * Removes given accessToken from the cache and from the key map\n * @param key\n */\n async removeAccessToken(key: string): Promise {\n void super.removeAccessToken(key);\n this.removeTokenKey(key, CredentialType.ACCESS_TOKEN);\n }\n\n /**\n * Removes given refreshToken from the cache and from the key map\n * @param key\n */\n removeRefreshToken(key: string): void {\n super.removeRefreshToken(key);\n this.removeTokenKey(key, CredentialType.REFRESH_TOKEN);\n }\n\n /**\n * Gets the keys for the cached tokens associated with this clientId\n * @returns\n */\n getTokenKeys(): TokenKeys {\n this.logger.trace(\"BrowserCacheManager.getTokenKeys called\");\n const item = this.getItem(\n `${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`\n );\n if (item) {\n const tokenKeys = this.validateAndParseJson(item);\n if (\n tokenKeys &&\n tokenKeys.hasOwnProperty(\"idToken\") &&\n tokenKeys.hasOwnProperty(\"accessToken\") &&\n tokenKeys.hasOwnProperty(\"refreshToken\")\n ) {\n return tokenKeys as TokenKeys;\n } else {\n this.logger.error(\n \"BrowserCacheManager.getTokenKeys - Token keys found but in an unknown format. Returning empty key map.\"\n );\n }\n } else {\n this.logger.verbose(\n \"BrowserCacheManager.getTokenKeys - No token keys found\"\n );\n }\n\n return {\n idToken: [],\n accessToken: [],\n refreshToken: [],\n };\n }\n\n /**\n * Adds the given key to the token key map\n * @param key\n * @param type\n */\n addTokenKey(key: string, type: CredentialType): void {\n this.logger.trace(\"BrowserCacheManager addTokenKey called\");\n const tokenKeys = this.getTokenKeys();\n\n switch (type) {\n case CredentialType.ID_TOKEN:\n if (tokenKeys.idToken.indexOf(key) === -1) {\n this.logger.info(\n \"BrowserCacheManager: addTokenKey - idToken added to map\"\n );\n tokenKeys.idToken.push(key);\n }\n break;\n case CredentialType.ACCESS_TOKEN:\n if (tokenKeys.accessToken.indexOf(key) === -1) {\n this.logger.info(\n \"BrowserCacheManager: addTokenKey - accessToken added to map\"\n );\n tokenKeys.accessToken.push(key);\n }\n break;\n case CredentialType.REFRESH_TOKEN:\n if (tokenKeys.refreshToken.indexOf(key) === -1) {\n this.logger.info(\n \"BrowserCacheManager: addTokenKey - refreshToken added to map\"\n );\n tokenKeys.refreshToken.push(key);\n }\n break;\n default:\n this.logger.error(\n `BrowserCacheManager:addTokenKey - CredentialType provided invalid. CredentialType: ${type}`\n );\n throw createClientAuthError(\n ClientAuthErrorCodes.unexpectedCredentialType\n );\n }\n\n this.setItem(\n `${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`,\n JSON.stringify(tokenKeys)\n );\n }\n\n /**\n * Removes the given key from the token key map\n * @param key\n * @param type\n */\n removeTokenKey(key: string, type: CredentialType): void {\n this.logger.trace(\"BrowserCacheManager removeTokenKey called\");\n const tokenKeys = this.getTokenKeys();\n\n switch (type) {\n case CredentialType.ID_TOKEN:\n this.logger.infoPii(\n `BrowserCacheManager: removeTokenKey - attempting to remove idToken with key: ${key} from map`\n );\n const idRemoval = tokenKeys.idToken.indexOf(key);\n if (idRemoval > -1) {\n this.logger.info(\n \"BrowserCacheManager: removeTokenKey - idToken removed from map\"\n );\n tokenKeys.idToken.splice(idRemoval, 1);\n } else {\n this.logger.info(\n \"BrowserCacheManager: removeTokenKey - idToken does not exist in map. Either it was previously removed or it was never added.\"\n );\n }\n break;\n case CredentialType.ACCESS_TOKEN:\n this.logger.infoPii(\n `BrowserCacheManager: removeTokenKey - attempting to remove accessToken with key: ${key} from map`\n );\n const accessRemoval = tokenKeys.accessToken.indexOf(key);\n if (accessRemoval > -1) {\n this.logger.info(\n \"BrowserCacheManager: removeTokenKey - accessToken removed from map\"\n );\n tokenKeys.accessToken.splice(accessRemoval, 1);\n } else {\n this.logger.info(\n \"BrowserCacheManager: removeTokenKey - accessToken does not exist in map. Either it was previously removed or it was never added.\"\n );\n }\n break;\n case CredentialType.REFRESH_TOKEN:\n this.logger.infoPii(\n `BrowserCacheManager: removeTokenKey - attempting to remove refreshToken with key: ${key} from map`\n );\n const refreshRemoval = tokenKeys.refreshToken.indexOf(key);\n if (refreshRemoval > -1) {\n this.logger.info(\n \"BrowserCacheManager: removeTokenKey - refreshToken removed from map\"\n );\n tokenKeys.refreshToken.splice(refreshRemoval, 1);\n } else {\n this.logger.info(\n \"BrowserCacheManager: removeTokenKey - refreshToken does not exist in map. Either it was previously removed or it was never added.\"\n );\n }\n break;\n default:\n this.logger.error(\n `BrowserCacheManager:removeTokenKey - CredentialType provided invalid. CredentialType: ${type}`\n );\n throw createClientAuthError(\n ClientAuthErrorCodes.unexpectedCredentialType\n );\n }\n\n this.setItem(\n `${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`,\n JSON.stringify(tokenKeys)\n );\n }\n\n /**\n * generates idToken entity from a string\n * @param idTokenKey\n */\n getIdTokenCredential(idTokenKey: string): IdTokenEntity | null {\n const value = this.getItem(idTokenKey);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getIdTokenCredential: called, no cache hit\"\n );\n this.removeTokenKey(idTokenKey, CredentialType.ID_TOKEN);\n return null;\n }\n\n const parsedIdToken = this.validateAndParseJson(value);\n if (!parsedIdToken || !CacheHelpers.isIdTokenEntity(parsedIdToken)) {\n this.logger.trace(\n \"BrowserCacheManager.getIdTokenCredential: called, no cache hit\"\n );\n this.removeTokenKey(idTokenKey, CredentialType.ID_TOKEN);\n return null;\n }\n\n this.logger.trace(\n \"BrowserCacheManager.getIdTokenCredential: cache hit\"\n );\n return parsedIdToken as IdTokenEntity;\n }\n\n /**\n * set IdToken credential to the platform cache\n * @param idToken\n */\n setIdTokenCredential(idToken: IdTokenEntity): void {\n this.logger.trace(\"BrowserCacheManager.setIdTokenCredential called\");\n const idTokenKey = CacheHelpers.generateCredentialKey(idToken);\n\n this.setItem(idTokenKey, JSON.stringify(idToken));\n\n this.addTokenKey(idTokenKey, CredentialType.ID_TOKEN);\n }\n\n /**\n * generates accessToken entity from a string\n * @param key\n */\n getAccessTokenCredential(accessTokenKey: string): AccessTokenEntity | null {\n const value = this.getItem(accessTokenKey);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getAccessTokenCredential: called, no cache hit\"\n );\n this.removeTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN);\n return null;\n }\n const parsedAccessToken = this.validateAndParseJson(value);\n if (\n !parsedAccessToken ||\n !CacheHelpers.isAccessTokenEntity(parsedAccessToken)\n ) {\n this.logger.trace(\n \"BrowserCacheManager.getAccessTokenCredential: called, no cache hit\"\n );\n this.removeTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN);\n return null;\n }\n\n this.logger.trace(\n \"BrowserCacheManager.getAccessTokenCredential: cache hit\"\n );\n return parsedAccessToken as AccessTokenEntity;\n }\n\n /**\n * set accessToken credential to the platform cache\n * @param accessToken\n */\n setAccessTokenCredential(accessToken: AccessTokenEntity): void {\n this.logger.trace(\n \"BrowserCacheManager.setAccessTokenCredential called\"\n );\n const accessTokenKey = CacheHelpers.generateCredentialKey(accessToken);\n this.setItem(accessTokenKey, JSON.stringify(accessToken));\n\n this.addTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN);\n }\n\n /**\n * generates refreshToken entity from a string\n * @param refreshTokenKey\n */\n getRefreshTokenCredential(\n refreshTokenKey: string\n ): RefreshTokenEntity | null {\n const value = this.getItem(refreshTokenKey);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getRefreshTokenCredential: called, no cache hit\"\n );\n this.removeTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN);\n return null;\n }\n const parsedRefreshToken = this.validateAndParseJson(value);\n if (\n !parsedRefreshToken ||\n !CacheHelpers.isRefreshTokenEntity(parsedRefreshToken)\n ) {\n this.logger.trace(\n \"BrowserCacheManager.getRefreshTokenCredential: called, no cache hit\"\n );\n this.removeTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN);\n return null;\n }\n\n this.logger.trace(\n \"BrowserCacheManager.getRefreshTokenCredential: cache hit\"\n );\n return parsedRefreshToken as RefreshTokenEntity;\n }\n\n /**\n * set refreshToken credential to the platform cache\n * @param refreshToken\n */\n setRefreshTokenCredential(refreshToken: RefreshTokenEntity): void {\n this.logger.trace(\n \"BrowserCacheManager.setRefreshTokenCredential called\"\n );\n const refreshTokenKey =\n CacheHelpers.generateCredentialKey(refreshToken);\n this.setItem(refreshTokenKey, JSON.stringify(refreshToken));\n\n this.addTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN);\n }\n\n /**\n * fetch appMetadata entity from the platform cache\n * @param appMetadataKey\n */\n getAppMetadata(appMetadataKey: string): AppMetadataEntity | null {\n const value = this.getItem(appMetadataKey);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getAppMetadata: called, no cache hit\"\n );\n return null;\n }\n\n const parsedMetadata = this.validateAndParseJson(value);\n if (\n !parsedMetadata ||\n !CacheHelpers.isAppMetadataEntity(appMetadataKey, parsedMetadata)\n ) {\n this.logger.trace(\n \"BrowserCacheManager.getAppMetadata: called, no cache hit\"\n );\n return null;\n }\n\n this.logger.trace(\"BrowserCacheManager.getAppMetadata: cache hit\");\n return parsedMetadata as AppMetadataEntity;\n }\n\n /**\n * set appMetadata entity to the platform cache\n * @param appMetadata\n */\n setAppMetadata(appMetadata: AppMetadataEntity): void {\n this.logger.trace(\"BrowserCacheManager.setAppMetadata called\");\n const appMetadataKey = CacheHelpers.generateAppMetadataKey(appMetadata);\n this.setItem(appMetadataKey, JSON.stringify(appMetadata));\n }\n\n /**\n * fetch server telemetry entity from the platform cache\n * @param serverTelemetryKey\n */\n getServerTelemetry(\n serverTelemetryKey: string\n ): ServerTelemetryEntity | null {\n const value = this.getItem(serverTelemetryKey);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getServerTelemetry: called, no cache hit\"\n );\n return null;\n }\n const parsedEntity = this.validateAndParseJson(value);\n if (\n !parsedEntity ||\n !CacheHelpers.isServerTelemetryEntity(\n serverTelemetryKey,\n parsedEntity\n )\n ) {\n this.logger.trace(\n \"BrowserCacheManager.getServerTelemetry: called, no cache hit\"\n );\n return null;\n }\n\n this.logger.trace(\"BrowserCacheManager.getServerTelemetry: cache hit\");\n return parsedEntity as ServerTelemetryEntity;\n }\n\n /**\n * set server telemetry entity to the platform cache\n * @param serverTelemetryKey\n * @param serverTelemetry\n */\n setServerTelemetry(\n serverTelemetryKey: string,\n serverTelemetry: ServerTelemetryEntity\n ): void {\n this.logger.trace(\"BrowserCacheManager.setServerTelemetry called\");\n this.setItem(serverTelemetryKey, JSON.stringify(serverTelemetry));\n }\n\n /**\n *\n */\n getAuthorityMetadata(key: string): AuthorityMetadataEntity | null {\n const value = this.internalStorage.getItem(key);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getAuthorityMetadata: called, no cache hit\"\n );\n return null;\n }\n const parsedMetadata = this.validateAndParseJson(value);\n if (\n parsedMetadata &&\n CacheHelpers.isAuthorityMetadataEntity(key, parsedMetadata)\n ) {\n this.logger.trace(\n \"BrowserCacheManager.getAuthorityMetadata: cache hit\"\n );\n return parsedMetadata as AuthorityMetadataEntity;\n }\n return null;\n }\n\n /**\n *\n */\n getAuthorityMetadataKeys(): Array {\n const allKeys = this.internalStorage.getKeys();\n return allKeys.filter((key) => {\n return this.isAuthorityMetadata(key);\n });\n }\n\n /**\n * Sets wrapper metadata in memory\n * @param wrapperSKU\n * @param wrapperVersion\n */\n setWrapperMetadata(wrapperSKU: string, wrapperVersion: string): void {\n this.internalStorage.setItem(InMemoryCacheKeys.WRAPPER_SKU, wrapperSKU);\n this.internalStorage.setItem(\n InMemoryCacheKeys.WRAPPER_VER,\n wrapperVersion\n );\n }\n\n /**\n * Returns wrapper metadata from in-memory storage\n */\n getWrapperMetadata(): [string, string] {\n const sku =\n this.internalStorage.getItem(InMemoryCacheKeys.WRAPPER_SKU) ||\n Constants.EMPTY_STRING;\n const version =\n this.internalStorage.getItem(InMemoryCacheKeys.WRAPPER_VER) ||\n Constants.EMPTY_STRING;\n return [sku, version];\n }\n\n /**\n *\n * @param entity\n */\n setAuthorityMetadata(key: string, entity: AuthorityMetadataEntity): void {\n this.logger.trace(\"BrowserCacheManager.setAuthorityMetadata called\");\n this.internalStorage.setItem(key, JSON.stringify(entity));\n }\n\n /**\n * Gets the active account\n */\n getActiveAccount(): AccountInfo | null {\n const activeAccountKeyFilters = this.generateCacheKey(\n PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS\n );\n const activeAccountValueFilters = this.getItem(activeAccountKeyFilters);\n if (!activeAccountValueFilters) {\n // if new active account cache type isn't found, it's an old version, so look for that instead\n this.logger.trace(\n \"BrowserCacheManager.getActiveAccount: No active account filters cache schema found, looking for legacy schema\"\n );\n const activeAccountKeyLocal = this.generateCacheKey(\n PersistentCacheKeys.ACTIVE_ACCOUNT\n );\n const activeAccountValueLocal = this.getItem(activeAccountKeyLocal);\n if (!activeAccountValueLocal) {\n this.logger.trace(\n \"BrowserCacheManager.getActiveAccount: No active account found\"\n );\n return null;\n }\n const activeAccount = this.getAccountInfoFilteredBy({\n localAccountId: activeAccountValueLocal,\n });\n if (activeAccount) {\n this.logger.trace(\n \"BrowserCacheManager.getActiveAccount: Legacy active account cache schema found\"\n );\n this.logger.trace(\n \"BrowserCacheManager.getActiveAccount: Adding active account filters cache schema\"\n );\n this.setActiveAccount(activeAccount);\n return activeAccount;\n }\n return null;\n }\n const activeAccountValueObj = this.validateAndParseJson(\n activeAccountValueFilters\n ) as AccountInfo;\n if (activeAccountValueObj) {\n this.logger.trace(\n \"BrowserCacheManager.getActiveAccount: Active account filters schema found\"\n );\n return this.getAccountInfoFilteredBy({\n homeAccountId: activeAccountValueObj.homeAccountId,\n localAccountId: activeAccountValueObj.localAccountId,\n tenantId: activeAccountValueObj.tenantId,\n });\n }\n this.logger.trace(\n \"BrowserCacheManager.getActiveAccount: No active account found\"\n );\n return null;\n }\n\n /**\n * Sets the active account's localAccountId in cache\n * @param account\n */\n setActiveAccount(account: AccountInfo | null): void {\n const activeAccountKey = this.generateCacheKey(\n PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS\n );\n const activeAccountKeyLocal = this.generateCacheKey(\n PersistentCacheKeys.ACTIVE_ACCOUNT\n );\n if (account) {\n this.logger.verbose(\"setActiveAccount: Active account set\");\n const activeAccountValue: ActiveAccountFilters = {\n homeAccountId: account.homeAccountId,\n localAccountId: account.localAccountId,\n tenantId: account.tenantId,\n };\n this.browserStorage.setItem(\n activeAccountKey,\n JSON.stringify(activeAccountValue)\n );\n this.browserStorage.setItem(\n activeAccountKeyLocal,\n account.localAccountId\n );\n } else {\n this.logger.verbose(\n \"setActiveAccount: No account passed, active account not set\"\n );\n this.browserStorage.removeItem(activeAccountKey);\n this.browserStorage.removeItem(activeAccountKeyLocal);\n }\n }\n\n /**\n * fetch throttling entity from the platform cache\n * @param throttlingCacheKey\n */\n getThrottlingCache(throttlingCacheKey: string): ThrottlingEntity | null {\n const value = this.getItem(throttlingCacheKey);\n if (!value) {\n this.logger.trace(\n \"BrowserCacheManager.getThrottlingCache: called, no cache hit\"\n );\n return null;\n }\n\n const parsedThrottlingCache = this.validateAndParseJson(value);\n if (\n !parsedThrottlingCache ||\n !CacheHelpers.isThrottlingEntity(\n throttlingCacheKey,\n parsedThrottlingCache\n )\n ) {\n this.logger.trace(\n \"BrowserCacheManager.getThrottlingCache: called, no cache hit\"\n );\n return null;\n }\n\n this.logger.trace(\"BrowserCacheManager.getThrottlingCache: cache hit\");\n return parsedThrottlingCache as ThrottlingEntity;\n }\n\n /**\n * set throttling entity to the platform cache\n * @param throttlingCacheKey\n * @param throttlingCache\n */\n setThrottlingCache(\n throttlingCacheKey: string,\n throttlingCache: ThrottlingEntity\n ): void {\n this.logger.trace(\"BrowserCacheManager.setThrottlingCache called\");\n this.setItem(throttlingCacheKey, JSON.stringify(throttlingCache));\n }\n\n /**\n * Gets cache item with given key.\n * Will retrieve from cookies if storeAuthStateInCookie is set to true.\n * @param key\n */\n getTemporaryCache(cacheKey: string, generateKey?: boolean): string | null {\n const key = generateKey ? this.generateCacheKey(cacheKey) : cacheKey;\n if (this.cacheConfig.storeAuthStateInCookie) {\n const itemCookie = this.getItemCookie(key);\n if (itemCookie) {\n this.logger.trace(\n \"BrowserCacheManager.getTemporaryCache: storeAuthStateInCookies set to true, retrieving from cookies\"\n );\n return itemCookie;\n }\n }\n\n const value = this.temporaryCacheStorage.getItem(key);\n if (!value) {\n // If temp cache item not found in session/memory, check local storage for items set by old versions\n if (\n this.cacheConfig.cacheLocation ===\n BrowserCacheLocation.LocalStorage\n ) {\n const item = this.browserStorage.getItem(key);\n if (item) {\n this.logger.trace(\n \"BrowserCacheManager.getTemporaryCache: Temporary cache item found in local storage\"\n );\n return item;\n }\n }\n this.logger.trace(\n \"BrowserCacheManager.getTemporaryCache: No cache item found in local storage\"\n );\n return null;\n }\n this.logger.trace(\n \"BrowserCacheManager.getTemporaryCache: Temporary cache item returned\"\n );\n return value;\n }\n\n /**\n * Sets the cache item with the key and value given.\n * Stores in cookie if storeAuthStateInCookie is set to true.\n * This can cause cookie overflow if used incorrectly.\n * @param key\n * @param value\n */\n setTemporaryCache(\n cacheKey: string,\n value: string,\n generateKey?: boolean\n ): void {\n const key = generateKey ? this.generateCacheKey(cacheKey) : cacheKey;\n\n this.temporaryCacheStorage.setItem(key, value);\n if (this.cacheConfig.storeAuthStateInCookie) {\n this.logger.trace(\n \"BrowserCacheManager.setTemporaryCache: storeAuthStateInCookie set to true, setting item cookie\"\n );\n this.setItemCookie(key, value);\n }\n }\n\n /**\n * Removes the cache item with the given key.\n * Will also clear the cookie item if storeAuthStateInCookie is set to true.\n * @param key\n */\n removeItem(key: string): void {\n this.browserStorage.removeItem(key);\n this.temporaryCacheStorage.removeItem(key);\n if (this.cacheConfig.storeAuthStateInCookie) {\n this.logger.trace(\n \"BrowserCacheManager.removeItem: storeAuthStateInCookie is true, clearing item cookie\"\n );\n this.clearItemCookie(key);\n }\n }\n\n /**\n * Checks whether key is in cache.\n * @param key\n */\n containsKey(key: string): boolean {\n return (\n this.browserStorage.containsKey(key) ||\n this.temporaryCacheStorage.containsKey(key)\n );\n }\n\n /**\n * Gets all keys in window.\n */\n getKeys(): string[] {\n return [\n ...this.browserStorage.getKeys(),\n ...this.temporaryCacheStorage.getKeys(),\n ];\n }\n\n /**\n * Clears all cache entries created by MSAL.\n */\n async clear(): Promise {\n // Removes all accounts and their credentials\n await this.removeAllAccounts();\n this.removeAppMetadata();\n\n // Removes all remaining MSAL cache items\n this.getKeys().forEach((cacheKey: string) => {\n // Check if key contains msal prefix; For now, we are clearing all the cache items created by MSAL.js\n if (\n (this.browserStorage.containsKey(cacheKey) ||\n this.temporaryCacheStorage.containsKey(cacheKey)) &&\n (cacheKey.indexOf(Constants.CACHE_PREFIX) !== -1 ||\n cacheKey.indexOf(this.clientId) !== -1)\n ) {\n this.removeItem(cacheKey);\n }\n });\n\n this.internalStorage.clear();\n }\n\n /**\n * Clears all access tokes that have claims prior to saving the current one\n * @param performanceClient {IPerformanceClient}\n * @returns\n */\n async clearTokensAndKeysWithClaims(\n performanceClient: IPerformanceClient\n ): Promise {\n performanceClient.addQueueMeasurement(\n PerformanceEvents.ClearTokensAndKeysWithClaims\n );\n\n const tokenKeys = this.getTokenKeys();\n\n const removedAccessTokens: Array> = [];\n tokenKeys.accessToken.forEach((key: string) => {\n // if the access token has claims in its key, remove the token key and the token\n const credential = this.getAccessTokenCredential(key);\n if (\n credential?.requestedClaimsHash &&\n key.includes(credential.requestedClaimsHash.toLowerCase())\n ) {\n removedAccessTokens.push(this.removeAccessToken(key));\n }\n });\n await Promise.all(removedAccessTokens);\n\n // warn if any access tokens are removed\n if (removedAccessTokens.length > 0) {\n this.logger.warning(\n `${removedAccessTokens.length} access tokens with claims in the cache keys have been removed from the cache.`\n );\n }\n }\n\n /**\n * Add value to cookies\n * @param cookieName\n * @param cookieValue\n * @param expires\n */\n setItemCookie(\n cookieName: string,\n cookieValue: string,\n expires?: number\n ): void {\n let cookieStr = `${encodeURIComponent(cookieName)}=${encodeURIComponent(\n cookieValue\n )};path=/;SameSite=Lax;`;\n if (expires) {\n const expireTime = this.getCookieExpirationTime(expires);\n cookieStr += `expires=${expireTime};`;\n }\n\n if (this.cacheConfig.secureCookies) {\n cookieStr += \"Secure;\";\n }\n\n document.cookie = cookieStr;\n }\n\n /**\n * Get one item by key from cookies\n * @param cookieName\n */\n getItemCookie(cookieName: string): string {\n const name = `${encodeURIComponent(cookieName)}=`;\n const cookieList = document.cookie.split(\";\");\n for (let i: number = 0; i < cookieList.length; i++) {\n let cookie = cookieList[i];\n while (cookie.charAt(0) === \" \") {\n cookie = cookie.substring(1);\n }\n if (cookie.indexOf(name) === 0) {\n return decodeURIComponent(\n cookie.substring(name.length, cookie.length)\n );\n }\n }\n return Constants.EMPTY_STRING;\n }\n\n /**\n * Clear all msal-related cookies currently set in the browser. Should only be used to clear temporary cache items.\n */\n clearMsalCookies(): void {\n const cookiePrefix = `${Constants.CACHE_PREFIX}.${this.clientId}`;\n const cookieList = document.cookie.split(\";\");\n cookieList.forEach((cookie: string): void => {\n while (cookie.charAt(0) === \" \") {\n // eslint-disable-next-line no-param-reassign\n cookie = cookie.substring(1);\n }\n if (cookie.indexOf(cookiePrefix) === 0) {\n const cookieKey = cookie.split(\"=\")[0];\n this.clearItemCookie(cookieKey);\n }\n });\n }\n\n /**\n * Clear an item in the cookies by key\n * @param cookieName\n */\n clearItemCookie(cookieName: string): void {\n this.setItemCookie(cookieName, Constants.EMPTY_STRING, -1);\n }\n\n /**\n * Get cookie expiration time\n * @param cookieLifeDays\n */\n getCookieExpirationTime(cookieLifeDays: number): string {\n const today = new Date();\n const expr = new Date(\n today.getTime() + cookieLifeDays * this.COOKIE_LIFE_MULTIPLIER\n );\n return expr.toUTCString();\n }\n\n /**\n * Gets the cache object referenced by the browser\n */\n getCache(): object {\n return this.browserStorage;\n }\n\n /**\n * interface compat, we cannot overwrite browser cache; Functionality is supported by individual entities in browser\n */\n setCache(): void {\n // sets nothing\n }\n\n /**\n * Prepend msal. to each key; Skip for any JSON object as Key (defined schemas do not need the key appended: AccessToken Keys or the upcoming schema)\n * @param key\n * @param addInstanceId\n */\n generateCacheKey(key: string): string {\n const generatedKey = this.validateAndParseJson(key);\n if (!generatedKey) {\n if (\n StringUtils.startsWith(key, Constants.CACHE_PREFIX) ||\n StringUtils.startsWith(key, PersistentCacheKeys.ADAL_ID_TOKEN)\n ) {\n return key;\n }\n return `${Constants.CACHE_PREFIX}.${this.clientId}.${key}`;\n }\n\n return JSON.stringify(key);\n }\n\n /**\n * Create authorityKey to cache authority\n * @param state\n */\n generateAuthorityKey(stateString: string): string {\n const {\n libraryState: { id: stateId },\n } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);\n\n return this.generateCacheKey(\n `${TemporaryCacheKeys.AUTHORITY}.${stateId}`\n );\n }\n\n /**\n * Create Nonce key to cache nonce\n * @param state\n */\n generateNonceKey(stateString: string): string {\n const {\n libraryState: { id: stateId },\n } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);\n\n return this.generateCacheKey(\n `${TemporaryCacheKeys.NONCE_IDTOKEN}.${stateId}`\n );\n }\n\n /**\n * Creates full cache key for the request state\n * @param stateString State string for the request\n */\n generateStateKey(stateString: string): string {\n // Use the library state id to key temp storage for uniqueness for multiple concurrent requests\n const {\n libraryState: { id: stateId },\n } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);\n return this.generateCacheKey(\n `${TemporaryCacheKeys.REQUEST_STATE}.${stateId}`\n );\n }\n\n /**\n * Gets the cached authority based on the cached state. Returns empty if no cached state found.\n */\n getCachedAuthority(cachedState: string): string | null {\n const stateCacheKey = this.generateStateKey(cachedState);\n const state = this.getTemporaryCache(stateCacheKey);\n if (!state) {\n return null;\n }\n\n const authorityCacheKey = this.generateAuthorityKey(state);\n return this.getTemporaryCache(authorityCacheKey);\n }\n\n /**\n * Updates account, authority, and state in cache\n * @param serverAuthenticationRequest\n * @param account\n */\n updateCacheEntries(\n state: string,\n nonce: string,\n authorityInstance: string,\n loginHint: string,\n account: AccountInfo | null\n ): void {\n this.logger.trace(\"BrowserCacheManager.updateCacheEntries called\");\n // Cache the request state\n const stateCacheKey = this.generateStateKey(state);\n this.setTemporaryCache(stateCacheKey, state, false);\n\n // Cache the nonce\n const nonceCacheKey = this.generateNonceKey(state);\n this.setTemporaryCache(nonceCacheKey, nonce, false);\n\n // Cache authorityKey\n const authorityCacheKey = this.generateAuthorityKey(state);\n this.setTemporaryCache(authorityCacheKey, authorityInstance, false);\n\n if (account) {\n const ccsCredential: CcsCredential = {\n credential: account.homeAccountId,\n type: CcsCredentialType.HOME_ACCOUNT_ID,\n };\n this.setTemporaryCache(\n TemporaryCacheKeys.CCS_CREDENTIAL,\n JSON.stringify(ccsCredential),\n true\n );\n } else if (loginHint) {\n const ccsCredential: CcsCredential = {\n credential: loginHint,\n type: CcsCredentialType.UPN,\n };\n this.setTemporaryCache(\n TemporaryCacheKeys.CCS_CREDENTIAL,\n JSON.stringify(ccsCredential),\n true\n );\n }\n }\n\n /**\n * Reset all temporary cache items\n * @param state\n */\n resetRequestCache(state: string): void {\n this.logger.trace(\"BrowserCacheManager.resetRequestCache called\");\n // check state and remove associated cache items\n if (state) {\n this.getKeys().forEach((key) => {\n if (key.indexOf(state) !== -1) {\n this.removeItem(key);\n }\n });\n\n // delete generic interactive request parameters\n this.removeItem(this.generateStateKey(state));\n this.removeItem(this.generateNonceKey(state));\n this.removeItem(this.generateAuthorityKey(state));\n }\n this.removeItem(\n this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS)\n );\n this.removeItem(this.generateCacheKey(TemporaryCacheKeys.ORIGIN_URI));\n this.removeItem(this.generateCacheKey(TemporaryCacheKeys.URL_HASH));\n this.removeItem(\n this.generateCacheKey(TemporaryCacheKeys.CORRELATION_ID)\n );\n this.removeItem(\n this.generateCacheKey(TemporaryCacheKeys.CCS_CREDENTIAL)\n );\n this.removeItem(\n this.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST)\n );\n this.setInteractionInProgress(false);\n }\n\n /**\n * Removes temporary cache for the provided state\n * @param stateString\n */\n cleanRequestByState(stateString: string): void {\n this.logger.trace(\"BrowserCacheManager.cleanRequestByState called\");\n // Interaction is completed - remove interaction status.\n if (stateString) {\n const stateKey = this.generateStateKey(stateString);\n const cachedState = this.temporaryCacheStorage.getItem(stateKey);\n this.logger.infoPii(\n `BrowserCacheManager.cleanRequestByState: Removing temporary cache items for state: ${cachedState}`\n );\n this.resetRequestCache(cachedState || Constants.EMPTY_STRING);\n }\n this.clearMsalCookies();\n }\n\n /**\n * Looks in temporary cache for any state values with the provided interactionType and removes all temporary cache items for that state\n * Used in scenarios where temp cache needs to be cleaned but state is not known, such as clicking browser back button.\n * @param interactionType\n */\n cleanRequestByInteractionType(interactionType: InteractionType): void {\n this.logger.trace(\n \"BrowserCacheManager.cleanRequestByInteractionType called\"\n );\n // Loop through all keys to find state key\n this.getKeys().forEach((key) => {\n // If this key is not the state key, move on\n if (key.indexOf(TemporaryCacheKeys.REQUEST_STATE) === -1) {\n return;\n }\n\n // Retrieve state value, return if not a valid value\n const stateValue = this.temporaryCacheStorage.getItem(key);\n if (!stateValue) {\n return;\n }\n // Extract state and ensure it matches given InteractionType, then clean request cache\n const parsedState = extractBrowserRequestState(\n this.cryptoImpl,\n stateValue\n );\n if (\n parsedState &&\n parsedState.interactionType === interactionType\n ) {\n this.logger.infoPii(\n `BrowserCacheManager.cleanRequestByInteractionType: Removing temporary cache items for state: ${stateValue}`\n );\n this.resetRequestCache(stateValue);\n }\n });\n this.clearMsalCookies();\n this.setInteractionInProgress(false);\n }\n\n cacheCodeRequest(authCodeRequest: CommonAuthorizationCodeRequest): void {\n this.logger.trace(\"BrowserCacheManager.cacheCodeRequest called\");\n\n const encodedValue = base64Encode(JSON.stringify(authCodeRequest));\n this.setTemporaryCache(\n TemporaryCacheKeys.REQUEST_PARAMS,\n encodedValue,\n true\n );\n }\n\n /**\n * Gets the token exchange parameters from the cache. Throws an error if nothing is found.\n */\n getCachedRequest(state: string): CommonAuthorizationCodeRequest {\n this.logger.trace(\"BrowserCacheManager.getCachedRequest called\");\n // Get token request from cache and parse as TokenExchangeParameters.\n const encodedTokenRequest = this.getTemporaryCache(\n TemporaryCacheKeys.REQUEST_PARAMS,\n true\n );\n if (!encodedTokenRequest) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.noTokenRequestCacheError\n );\n }\n\n let parsedRequest: CommonAuthorizationCodeRequest;\n try {\n parsedRequest = JSON.parse(base64Decode(encodedTokenRequest));\n } catch (e) {\n this.logger.errorPii(`Attempted to parse: ${encodedTokenRequest}`);\n this.logger.error(\n `Parsing cached token request threw with error: ${e}`\n );\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.unableToParseTokenRequestCacheError\n );\n }\n this.removeItem(\n this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS)\n );\n\n // Get cached authority and use if no authority is cached with request.\n if (!parsedRequest.authority) {\n const authorityCacheKey: string = this.generateAuthorityKey(state);\n const cachedAuthority = this.getTemporaryCache(authorityCacheKey);\n if (!cachedAuthority) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.noCachedAuthorityError\n );\n }\n parsedRequest.authority = cachedAuthority;\n }\n\n return parsedRequest;\n }\n\n /**\n * Gets cached native request for redirect flows\n */\n getCachedNativeRequest(): NativeTokenRequest | null {\n this.logger.trace(\"BrowserCacheManager.getCachedNativeRequest called\");\n const cachedRequest = this.getTemporaryCache(\n TemporaryCacheKeys.NATIVE_REQUEST,\n true\n );\n if (!cachedRequest) {\n this.logger.trace(\n \"BrowserCacheManager.getCachedNativeRequest: No cached native request found\"\n );\n return null;\n }\n\n const parsedRequest = this.validateAndParseJson(\n cachedRequest\n ) as NativeTokenRequest;\n if (!parsedRequest) {\n this.logger.error(\n \"BrowserCacheManager.getCachedNativeRequest: Unable to parse native request\"\n );\n return null;\n }\n\n return parsedRequest;\n }\n\n isInteractionInProgress(matchClientId?: boolean): boolean {\n const clientId = this.getInteractionInProgress();\n\n if (matchClientId) {\n return clientId === this.clientId;\n } else {\n return !!clientId;\n }\n }\n\n getInteractionInProgress(): string | null {\n const key = `${Constants.CACHE_PREFIX}.${TemporaryCacheKeys.INTERACTION_STATUS_KEY}`;\n return this.getTemporaryCache(key, false);\n }\n\n setInteractionInProgress(inProgress: boolean): void {\n // Ensure we don't overwrite interaction in progress for a different clientId\n const key = `${Constants.CACHE_PREFIX}.${TemporaryCacheKeys.INTERACTION_STATUS_KEY}`;\n if (inProgress) {\n if (this.getInteractionInProgress()) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.interactionInProgress\n );\n } else {\n // No interaction is in progress\n this.setTemporaryCache(key, this.clientId, false);\n }\n } else if (\n !inProgress &&\n this.getInteractionInProgress() === this.clientId\n ) {\n this.removeItem(key);\n }\n }\n\n /**\n * Returns username retrieved from ADAL or MSAL v1 idToken\n * @deprecated\n */\n getLegacyLoginHint(): string | null {\n // Only check for adal/msal token if no SSO params are being used\n const adalIdTokenString = this.getTemporaryCache(\n PersistentCacheKeys.ADAL_ID_TOKEN\n );\n if (adalIdTokenString) {\n this.browserStorage.removeItem(PersistentCacheKeys.ADAL_ID_TOKEN);\n this.logger.verbose(\"Cached ADAL id token retrieved.\");\n }\n\n // Check for cached MSAL v1 id token\n const msalIdTokenString = this.getTemporaryCache(\n PersistentCacheKeys.ID_TOKEN,\n true\n );\n if (msalIdTokenString) {\n this.removeItem(\n this.generateCacheKey(PersistentCacheKeys.ID_TOKEN)\n );\n this.logger.verbose(\"Cached MSAL.js v1 id token retrieved\");\n }\n\n const cachedIdTokenString = msalIdTokenString || adalIdTokenString;\n if (cachedIdTokenString) {\n const idTokenClaims = AuthToken.extractTokenClaims(\n cachedIdTokenString,\n base64Decode\n );\n if (idTokenClaims.preferred_username) {\n this.logger.verbose(\n \"No SSO params used and ADAL/MSAL v1 token retrieved, setting ADAL/MSAL v1 preferred_username as loginHint\"\n );\n return idTokenClaims.preferred_username;\n } else if (idTokenClaims.upn) {\n this.logger.verbose(\n \"No SSO params used and ADAL/MSAL v1 token retrieved, setting ADAL/MSAL v1 upn as loginHint\"\n );\n return idTokenClaims.upn;\n } else {\n this.logger.verbose(\n \"No SSO params used and ADAL/MSAL v1 token retrieved, however, no account hint claim found. Enable preferred_username or upn id token claim to get SSO.\"\n );\n }\n }\n\n return null;\n }\n\n /**\n * Updates a credential's cache key if the current cache key is outdated\n */\n updateCredentialCacheKey(\n currentCacheKey: string,\n credential: ValidCredentialType\n ): string {\n const updatedCacheKey = CacheHelpers.generateCredentialKey(credential);\n\n if (currentCacheKey !== updatedCacheKey) {\n const cacheItem = this.getItem(currentCacheKey);\n if (cacheItem) {\n this.removeItem(currentCacheKey);\n this.setItem(updatedCacheKey, cacheItem);\n this.logger.verbose(\n `Updated an outdated ${credential.credentialType} cache key`\n );\n return updatedCacheKey;\n } else {\n this.logger.error(\n `Attempted to update an outdated ${credential.credentialType} cache key but no item matching the outdated key was found in storage`\n );\n }\n }\n\n return currentCacheKey;\n }\n\n /**\n * Returns application id as redirect context during AcquireTokenRedirect flow.\n */\n getRedirectRequestContext(): string | null {\n return this.getTemporaryCache(\n TemporaryCacheKeys.REDIRECT_CONTEXT,\n true\n );\n }\n\n /**\n * Sets application id as the redirect context during AcquireTokenRedirect flow.\n * @param value\n */\n setRedirectRequestContext(value: string): void {\n this.setTemporaryCache(\n TemporaryCacheKeys.REDIRECT_CONTEXT,\n value,\n true\n );\n }\n\n /**\n * Builds credential entities from AuthenticationResult object and saves the resulting credentials to the cache\n * @param result\n * @param request\n */\n async hydrateCache(\n result: AuthenticationResult,\n request:\n | SilentRequest\n | SsoSilentRequest\n | RedirectRequest\n | PopupRequest\n ): Promise {\n const idTokenEntity = CacheHelpers.createIdTokenEntity(\n result.account?.homeAccountId,\n result.account?.environment,\n result.idToken,\n this.clientId,\n result.tenantId\n );\n\n let claimsHash;\n if (request.claims) {\n claimsHash = await this.cryptoImpl.hashString(request.claims);\n }\n const accessTokenEntity = CacheHelpers.createAccessTokenEntity(\n result.account?.homeAccountId,\n result.account.environment,\n result.accessToken,\n this.clientId,\n result.tenantId,\n result.scopes.join(\" \"),\n result.expiresOn?.getTime() || 0,\n result.extExpiresOn?.getTime() || 0,\n base64Decode,\n undefined, // refreshOn\n result.tokenType as AuthenticationScheme,\n undefined, // userAssertionHash\n request.sshKid,\n request.claims,\n claimsHash\n );\n\n const cacheRecord = new CacheRecord(\n undefined,\n idTokenEntity,\n accessTokenEntity\n );\n return this.saveCacheRecord(cacheRecord);\n }\n}\n\nexport const DEFAULT_BROWSER_CACHE_MANAGER = (\n clientId: string,\n logger: Logger\n): BrowserCacheManager => {\n const cacheOptions: Required = {\n cacheLocation: BrowserCacheLocation.MemoryStorage,\n temporaryCacheLocation: BrowserCacheLocation.MemoryStorage,\n storeAuthStateInCookie: false,\n secureCookies: false,\n cacheMigrationEnabled: false,\n claimsBasedCachingEnabled: false,\n };\n return new BrowserCacheManager(\n clientId,\n cacheOptions,\n DEFAULT_CRYPTO_IMPLEMENTATION,\n logger\n );\n};\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { UrlString } from \"@azure/msal-common\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../error/BrowserAuthError\";\nimport { InteractionType, BrowserConstants } from \"./BrowserConstants\";\nimport * as BrowserCrypto from \"../crypto/BrowserCrypto\";\n\n/**\n * Clears hash from window url.\n */\nexport function clearHash(contentWindow: Window): void {\n // Office.js sets history.replaceState to null\n contentWindow.location.hash = \"\";\n if (typeof contentWindow.history.replaceState === \"function\") {\n // Full removes \"#\" from url\n contentWindow.history.replaceState(\n null,\n \"\",\n `${contentWindow.location.origin}${contentWindow.location.pathname}${contentWindow.location.search}`\n );\n }\n}\n\n/**\n * Replaces current hash with hash from provided url\n */\nexport function replaceHash(url: string): void {\n const urlParts = url.split(\"#\");\n urlParts.shift(); // Remove part before the hash\n window.location.hash = urlParts.length > 0 ? urlParts.join(\"#\") : \"\";\n}\n\n/**\n * Returns boolean of whether the current window is in an iframe or not.\n */\nexport function isInIframe(): boolean {\n return window.parent !== window;\n}\n\n/**\n * Returns boolean of whether or not the current window is a popup opened by msal\n */\nexport function isInPopup(): boolean {\n return (\n typeof window !== \"undefined\" &&\n !!window.opener &&\n window.opener !== window &&\n typeof window.name === \"string\" &&\n window.name.indexOf(`${BrowserConstants.POPUP_NAME_PREFIX}.`) === 0\n );\n}\n\n// #endregion\n\n/**\n * Returns current window URL as redirect uri\n */\nexport function getCurrentUri(): string {\n return window.location.href.split(\"?\")[0].split(\"#\")[0];\n}\n\n/**\n * Gets the homepage url for the current window location.\n */\nexport function getHomepage(): string {\n const currentUrl = new UrlString(window.location.href);\n const urlComponents = currentUrl.getUrlComponents();\n return `${urlComponents.Protocol}//${urlComponents.HostNameAndPort}/`;\n}\n\n/**\n * Throws error if we have completed an auth and are\n * attempting another auth request inside an iframe.\n */\nexport function blockReloadInHiddenIframes(): void {\n const isResponseHash = UrlString.hashContainsKnownProperties(\n window.location.hash\n );\n // return an error if called from the hidden iframe created by the msal js silent calls\n if (isResponseHash && isInIframe()) {\n throw createBrowserAuthError(BrowserAuthErrorCodes.blockIframeReload);\n }\n}\n\n/**\n * Block redirect operations in iframes unless explicitly allowed\n * @param interactionType Interaction type for the request\n * @param allowRedirectInIframe Config value to allow redirects when app is inside an iframe\n */\nexport function blockRedirectInIframe(\n interactionType: InteractionType,\n allowRedirectInIframe: boolean\n): void {\n const isIframedApp = isInIframe();\n if (\n interactionType === InteractionType.Redirect &&\n isIframedApp &&\n !allowRedirectInIframe\n ) {\n // If we are not in top frame, we shouldn't redirect. This is also handled by the service.\n throw createBrowserAuthError(BrowserAuthErrorCodes.redirectInIframe);\n }\n}\n\n/**\n * Block redirectUri loaded in popup from calling AcquireToken APIs\n */\nexport function blockAcquireTokenInPopups(): void {\n // Popups opened by msal popup APIs are given a name that starts with \"msal.\"\n if (isInPopup()) {\n throw createBrowserAuthError(BrowserAuthErrorCodes.blockNestedPopups);\n }\n}\n\n/**\n * Throws error if token requests are made in non-browser environment\n * @param isBrowserEnvironment Flag indicating if environment is a browser.\n */\nexport function blockNonBrowserEnvironment(\n isBrowserEnvironment: boolean\n): void {\n if (!isBrowserEnvironment) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.nonBrowserEnvironment\n );\n }\n}\n\n/**\n * Throws error if initialize hasn't been called\n * @param initialized\n */\nexport function blockAPICallsBeforeInitialize(initialized: boolean): void {\n if (!initialized) {\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.uninitializedPublicClientApplication\n );\n }\n}\n\n/**\n * Adds a preconnect link element to the header which begins DNS resolution and SSL connection in anticipation of the /token request\n * @param loginDomain Authority domain, including https protocol e.g. https://login.microsoftonline.com\n * @returns\n */\nexport function preconnect(authority: string): void {\n const link = document.createElement(\"link\");\n link.rel = \"preconnect\";\n link.href = new URL(authority).origin;\n link.crossOrigin = \"anonymous\";\n document.head.appendChild(link);\n\n // The browser will close connection if not used within a few seconds, remove element from the header after 10s\n window.setTimeout(() => {\n try {\n document.head.removeChild(link);\n } catch {}\n }, 10000); // 10s Timeout\n}\n\n/**\n * Wrapper function that creates a UUID v7 from the current timestamp.\n * @returns {string}\n */\nexport function createGuid(): string {\n return BrowserCrypto.createNewGuid();\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NetworkResponse } from \"./NetworkManager\";\nimport { ServerAuthorizationTokenResponse } from \"../response/ServerAuthorizationTokenResponse\";\nimport {\n HeaderNames,\n ThrottlingConstants,\n Constants,\n} from \"../utils/Constants\";\nimport { CacheManager } from \"../cache/CacheManager\";\nimport { ServerError } from \"../error/ServerError\";\nimport { RequestThumbprint } from \"./RequestThumbprint\";\nimport { ThrottlingEntity } from \"../cache/entities/ThrottlingEntity\";\nimport { BaseAuthRequest } from \"../request/BaseAuthRequest\";\n\n/** @internal */\nexport class ThrottlingUtils {\n /**\n * Prepares a RequestThumbprint to be stored as a key.\n * @param thumbprint\n */\n static generateThrottlingStorageKey(thumbprint: RequestThumbprint): string {\n return `${ThrottlingConstants.THROTTLING_PREFIX}.${JSON.stringify(\n thumbprint\n )}`;\n }\n\n /**\n * Performs necessary throttling checks before a network request.\n * @param cacheManager\n * @param thumbprint\n */\n static preProcess(\n cacheManager: CacheManager,\n thumbprint: RequestThumbprint\n ): void {\n const key = ThrottlingUtils.generateThrottlingStorageKey(thumbprint);\n const value = cacheManager.getThrottlingCache(key);\n\n if (value) {\n if (value.throttleTime < Date.now()) {\n cacheManager.removeItem(key);\n return;\n }\n throw new ServerError(\n value.errorCodes?.join(\" \") || Constants.EMPTY_STRING,\n value.errorMessage,\n value.subError\n );\n }\n }\n\n /**\n * Performs necessary throttling checks after a network request.\n * @param cacheManager\n * @param thumbprint\n * @param response\n */\n static postProcess(\n cacheManager: CacheManager,\n thumbprint: RequestThumbprint,\n response: NetworkResponse\n ): void {\n if (\n ThrottlingUtils.checkResponseStatus(response) ||\n ThrottlingUtils.checkResponseForRetryAfter(response)\n ) {\n const thumbprintValue: ThrottlingEntity = {\n throttleTime: ThrottlingUtils.calculateThrottleTime(\n parseInt(response.headers[HeaderNames.RETRY_AFTER])\n ),\n error: response.body.error,\n errorCodes: response.body.error_codes,\n errorMessage: response.body.error_description,\n subError: response.body.suberror,\n };\n cacheManager.setThrottlingCache(\n ThrottlingUtils.generateThrottlingStorageKey(thumbprint),\n thumbprintValue\n );\n }\n }\n\n /**\n * Checks a NetworkResponse object's status codes against 429 or 5xx\n * @param response\n */\n static checkResponseStatus(\n response: NetworkResponse\n ): boolean {\n return (\n response.status === 429 ||\n (response.status >= 500 && response.status < 600)\n );\n }\n\n /**\n * Checks a NetworkResponse object's RetryAfter header\n * @param response\n */\n static checkResponseForRetryAfter(\n response: NetworkResponse\n ): boolean {\n if (response.headers) {\n return (\n response.headers.hasOwnProperty(HeaderNames.RETRY_AFTER) &&\n (response.status < 200 || response.status >= 300)\n );\n }\n return false;\n }\n\n /**\n * Calculates the Unix-time value for a throttle to expire given throttleTime in seconds.\n * @param throttleTime\n */\n static calculateThrottleTime(throttleTime: number): number {\n const time = throttleTime <= 0 ? 0 : throttleTime;\n\n const currentSeconds = Date.now() / 1000;\n return Math.floor(\n Math.min(\n currentSeconds +\n (time || ThrottlingConstants.DEFAULT_THROTTLE_TIME_SECONDS),\n currentSeconds +\n ThrottlingConstants.DEFAULT_MAX_THROTTLE_TIME_SECONDS\n ) * 1000\n );\n }\n\n static removeThrottle(\n cacheManager: CacheManager,\n clientId: string,\n request: BaseAuthRequest,\n homeAccountIdentifier?: string\n ): void {\n const thumbprint: RequestThumbprint = {\n clientId: clientId,\n authority: request.authority,\n scopes: request.scopes,\n homeAccountIdentifier: homeAccountIdentifier,\n claims: request.claims,\n authenticationScheme: request.authenticationScheme,\n resourceRequestMethod: request.resourceRequestMethod,\n resourceRequestUri: request.resourceRequestUri,\n shrClaims: request.shrClaims,\n sshKid: request.sshKid,\n };\n\n const key = this.generateThrottlingStorageKey(thumbprint);\n cacheManager.removeItem(key);\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { INetworkModule, NetworkRequestOptions } from \"./INetworkModule\";\nimport { RequestThumbprint } from \"./RequestThumbprint\";\nimport { ThrottlingUtils } from \"./ThrottlingUtils\";\nimport { CacheManager } from \"../cache/CacheManager\";\nimport { AuthError } from \"../error/AuthError\";\nimport {\n ClientAuthErrorCodes,\n createClientAuthError,\n} from \"../error/ClientAuthError\";\nimport { ServerAuthorizationTokenResponse } from \"../response/ServerAuthorizationTokenResponse\";\n\nexport type NetworkResponse = {\n headers: Record;\n body: T;\n status: number;\n};\n\nexport type UrlToHttpRequestOptions = {\n protocol: string;\n hostname: string;\n hash: string;\n search: string;\n pathname: string;\n path: string;\n href: string;\n port?: number;\n auth?: string;\n};\n\n/** @internal */\nexport class NetworkManager {\n private networkClient: INetworkModule;\n private cacheManager: CacheManager;\n\n constructor(networkClient: INetworkModule, cacheManager: CacheManager) {\n this.networkClient = networkClient;\n this.cacheManager = cacheManager;\n }\n\n /**\n * Wraps sendPostRequestAsync with necessary preflight and postflight logic\n * @param thumbprint\n * @param tokenEndpoint\n * @param options\n */\n async sendPostRequest(\n thumbprint: RequestThumbprint,\n tokenEndpoint: string,\n options: NetworkRequestOptions\n ): Promise> {\n ThrottlingUtils.preProcess(this.cacheManager, thumbprint);\n\n let response;\n try {\n response = await this.networkClient.sendPostRequestAsync(\n tokenEndpoint,\n options\n );\n } catch (e) {\n if (e instanceof AuthError) {\n throw e;\n } else {\n throw createClientAuthError(ClientAuthErrorCodes.networkError);\n }\n }\n\n ThrottlingUtils.postProcess(this.cacheManager, thumbprint, response);\n\n return response;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { Authority, formatAuthorityUri } from \"./Authority\";\nimport { INetworkModule } from \"../network/INetworkModule\";\nimport {\n createClientAuthError,\n ClientAuthErrorCodes,\n} from \"../error/ClientAuthError\";\nimport { ICacheManager } from \"../cache/interface/ICacheManager\";\nimport { AuthorityOptions } from \"./AuthorityOptions\";\nimport { Logger } from \"../logger/Logger\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { invokeAsync } from \"../utils/FunctionWrappers\";\n\n/**\n * Create an authority object of the correct type based on the url\n * Performs basic authority validation - checks to see if the authority is of a valid type (i.e. aad, b2c, adfs)\n *\n * Also performs endpoint discovery.\n *\n * @param authorityUri\n * @param networkClient\n * @param protocolMode\n * @internal\n */\nexport async function createDiscoveredInstance(\n authorityUri: string,\n networkClient: INetworkModule,\n cacheManager: ICacheManager,\n authorityOptions: AuthorityOptions,\n logger: Logger,\n correlationId: string,\n performanceClient?: IPerformanceClient\n): Promise {\n performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthorityFactoryCreateDiscoveredInstance,\n correlationId\n );\n const authorityUriFinal = Authority.transformCIAMAuthority(\n formatAuthorityUri(authorityUri)\n );\n\n // Initialize authority and perform discovery endpoint check.\n const acquireTokenAuthority: Authority = new Authority(\n authorityUriFinal,\n networkClient,\n cacheManager,\n authorityOptions,\n logger,\n correlationId,\n performanceClient\n );\n\n try {\n await invokeAsync(\n acquireTokenAuthority.resolveEndpointsAsync.bind(\n acquireTokenAuthority\n ),\n PerformanceEvents.AuthorityResolveEndpointsAsync,\n logger,\n performanceClient,\n correlationId\n )();\n return acquireTokenAuthority;\n } catch (e) {\n throw createClientAuthError(\n ClientAuthErrorCodes.endpointResolutionError\n );\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n ClientConfiguration,\n buildClientConfiguration,\n CommonClientConfiguration,\n} from \"../config/ClientConfiguration\";\nimport { INetworkModule } from \"../network/INetworkModule\";\nimport { NetworkManager, NetworkResponse } from \"../network/NetworkManager\";\nimport { ICrypto } from \"../crypto/ICrypto\";\nimport { Authority } from \"../authority/Authority\";\nimport { Logger } from \"../logger/Logger\";\nimport { Constants, HeaderNames } from \"../utils/Constants\";\nimport { ServerAuthorizationTokenResponse } from \"../response/ServerAuthorizationTokenResponse\";\nimport { CacheManager } from \"../cache/CacheManager\";\nimport { ServerTelemetryManager } from \"../telemetry/server/ServerTelemetryManager\";\nimport { RequestThumbprint } from \"../network/RequestThumbprint\";\nimport { version, name } from \"../packageMetadata\";\nimport { CcsCredential, CcsCredentialType } from \"../account/CcsCredential\";\nimport { buildClientInfoFromHomeAccountId } from \"../account/ClientInfo\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { RequestParameterBuilder } from \"../request/RequestParameterBuilder\";\nimport { BaseAuthRequest } from \"../request/BaseAuthRequest\";\nimport { createDiscoveredInstance } from \"../authority/AuthorityFactory\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\n\n/**\n * Base application class which will construct requests to send to and handle responses from the Microsoft STS using the authorization code flow.\n * @internal\n */\nexport abstract class BaseClient {\n // Logger object\n public logger: Logger;\n\n // Application config\n protected config: CommonClientConfiguration;\n\n // Crypto Interface\n protected cryptoUtils: ICrypto;\n\n // Storage Interface\n protected cacheManager: CacheManager;\n\n // Network Interface\n protected networkClient: INetworkModule;\n\n // Server Telemetry Manager\n protected serverTelemetryManager: ServerTelemetryManager | null;\n\n // Network Manager\n protected networkManager: NetworkManager;\n\n // Default authority object\n public authority: Authority;\n\n // Performance telemetry client\n protected performanceClient?: IPerformanceClient;\n\n protected constructor(\n configuration: ClientConfiguration,\n performanceClient?: IPerformanceClient\n ) {\n // Set the configuration\n this.config = buildClientConfiguration(configuration);\n\n // Initialize the logger\n this.logger = new Logger(this.config.loggerOptions, name, version);\n\n // Initialize crypto\n this.cryptoUtils = this.config.cryptoInterface;\n\n // Initialize storage interface\n this.cacheManager = this.config.storageInterface;\n\n // Set the network interface\n this.networkClient = this.config.networkInterface;\n\n // Set the NetworkManager\n this.networkManager = new NetworkManager(\n this.networkClient,\n this.cacheManager\n );\n\n // Set TelemetryManager\n this.serverTelemetryManager = this.config.serverTelemetryManager;\n\n // set Authority\n this.authority = this.config.authOptions.authority;\n\n // set performance telemetry client\n this.performanceClient = performanceClient;\n }\n\n /**\n * Creates default headers for requests to token endpoint\n */\n protected createTokenRequestHeaders(\n ccsCred?: CcsCredential\n ): Record {\n const headers: Record = {};\n headers[HeaderNames.CONTENT_TYPE] = Constants.URL_FORM_CONTENT_TYPE;\n if (!this.config.systemOptions.preventCorsPreflight && ccsCred) {\n switch (ccsCred.type) {\n case CcsCredentialType.HOME_ACCOUNT_ID:\n try {\n const clientInfo = buildClientInfoFromHomeAccountId(\n ccsCred.credential\n );\n headers[\n HeaderNames.CCS_HEADER\n ] = `Oid:${clientInfo.uid}@${clientInfo.utid}`;\n } catch (e) {\n this.logger.verbose(\n \"Could not parse home account ID for CCS Header: \" +\n e\n );\n }\n break;\n case CcsCredentialType.UPN:\n headers[\n HeaderNames.CCS_HEADER\n ] = `UPN: ${ccsCred.credential}`;\n break;\n }\n }\n return headers;\n }\n\n /**\n * Http post to token endpoint\n * @param tokenEndpoint\n * @param queryString\n * @param headers\n * @param thumbprint\n */\n protected async executePostToTokenEndpoint(\n tokenEndpoint: string,\n queryString: string,\n headers: Record,\n thumbprint: RequestThumbprint,\n correlationId: string,\n queuedEvent?: string\n ): Promise> {\n if (queuedEvent) {\n this.performanceClient?.addQueueMeasurement(\n queuedEvent,\n correlationId\n );\n }\n\n const response =\n await this.networkManager.sendPostRequest(\n thumbprint,\n tokenEndpoint,\n { body: queryString, headers: headers }\n );\n this.performanceClient?.addFields(\n {\n refreshTokenSize: response.body.refresh_token?.length || 0,\n httpVerToken:\n response.headers?.[HeaderNames.X_MS_HTTP_VERSION] || \"\",\n },\n correlationId\n );\n\n if (\n this.config.serverTelemetryManager &&\n response.status < 500 &&\n response.status !== 429\n ) {\n // Telemetry data successfully logged by server, clear Telemetry cache\n this.config.serverTelemetryManager.clearTelemetryCache();\n }\n\n return response;\n }\n\n /**\n * Updates the authority object of the client. Endpoint discovery must be completed.\n * @param updatedAuthority\n */\n async updateAuthority(\n cloudInstanceHostname: string,\n correlationId: string\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.UpdateTokenEndpointAuthority,\n correlationId\n );\n const cloudInstanceAuthorityUri = `https://${cloudInstanceHostname}/${this.authority.tenant}/`;\n const cloudInstanceAuthority = await createDiscoveredInstance(\n cloudInstanceAuthorityUri,\n this.networkClient,\n this.cacheManager,\n this.authority.options,\n this.logger,\n correlationId,\n this.performanceClient\n );\n this.authority = cloudInstanceAuthority;\n }\n\n /**\n * Creates query string for the /token request\n * @param request\n */\n createTokenQueryParameters(request: BaseAuthRequest): string {\n const parameterBuilder = new RequestParameterBuilder();\n\n if (request.tokenQueryParameters) {\n parameterBuilder.addExtraQueryParameters(\n request.tokenQueryParameters\n );\n }\n\n return parameterBuilder.createQueryString();\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ICrypto, SignedHttpRequestParameters } from \"./ICrypto\";\nimport * as TimeUtils from \"../utils/TimeUtils\";\nimport { UrlString } from \"../url/UrlString\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { invokeAsync } from \"../utils/FunctionWrappers\";\nimport { Logger } from \"../logger/Logger\";\n\n/**\n * See eSTS docs for more info.\n * - A kid element, with the value containing an RFC 7638-compliant JWK thumbprint that is base64 encoded.\n * - xms_ksl element, representing the storage location of the key's secret component on the client device. One of two values:\n * - sw: software storage\n * - uhw: hardware storage\n */\ntype ReqCnf = {\n kid: string;\n xms_ksl: KeyLocation;\n};\n\nexport type ReqCnfData = {\n kid: string;\n reqCnfString: string;\n reqCnfHash: string;\n};\n\nconst KeyLocation = {\n SW: \"sw\",\n UHW: \"uhw\",\n} as const;\nexport type KeyLocation = (typeof KeyLocation)[keyof typeof KeyLocation];\n\n/** @internal */\nexport class PopTokenGenerator {\n private cryptoUtils: ICrypto;\n private performanceClient?: IPerformanceClient;\n\n constructor(cryptoUtils: ICrypto, performanceClient?: IPerformanceClient) {\n this.cryptoUtils = cryptoUtils;\n this.performanceClient = performanceClient;\n }\n\n /**\n * Generates the req_cnf validated at the RP in the POP protocol for SHR parameters\n * and returns an object containing the keyid, the full req_cnf string and the req_cnf string hash\n * @param request\n * @returns\n */\n async generateCnf(\n request: SignedHttpRequestParameters,\n logger: Logger\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.PopTokenGenerateCnf,\n request.correlationId\n );\n\n const reqCnf = await invokeAsync(\n this.generateKid.bind(this),\n PerformanceEvents.PopTokenGenerateCnf,\n logger,\n this.performanceClient,\n request.correlationId\n )(request);\n const reqCnfString: string = this.cryptoUtils.base64Encode(\n JSON.stringify(reqCnf)\n );\n\n return {\n kid: reqCnf.kid,\n reqCnfString,\n reqCnfHash: await this.cryptoUtils.hashString(reqCnfString),\n };\n }\n\n /**\n * Generates key_id for a SHR token request\n * @param request\n * @returns\n */\n async generateKid(request: SignedHttpRequestParameters): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.PopTokenGenerateKid,\n request.correlationId\n );\n\n const kidThumbprint = await this.cryptoUtils.getPublicKeyThumbprint(\n request\n );\n\n return {\n kid: kidThumbprint,\n xms_ksl: KeyLocation.SW,\n };\n }\n\n /**\n * Signs the POP access_token with the local generated key-pair\n * @param accessToken\n * @param request\n * @returns\n */\n async signPopToken(\n accessToken: string,\n keyId: string,\n request: SignedHttpRequestParameters\n ): Promise {\n return this.signPayload(accessToken, keyId, request);\n }\n\n /**\n * Utility function to generate the signed JWT for an access_token\n * @param payload\n * @param kid\n * @param request\n * @param claims\n * @returns\n */\n async signPayload(\n payload: string,\n keyId: string,\n request: SignedHttpRequestParameters,\n claims?: object\n ): Promise {\n // Deconstruct request to extract SHR parameters\n const {\n resourceRequestMethod,\n resourceRequestUri,\n shrClaims,\n shrNonce,\n shrOptions,\n } = request;\n\n const resourceUrlString = resourceRequestUri\n ? new UrlString(resourceRequestUri)\n : undefined;\n const resourceUrlComponents = resourceUrlString?.getUrlComponents();\n return this.cryptoUtils.signJwt(\n {\n at: payload,\n ts: TimeUtils.nowSeconds(),\n m: resourceRequestMethod?.toUpperCase(),\n u: resourceUrlComponents?.HostNameAndPort,\n nonce: shrNonce || this.cryptoUtils.createNewGuid(),\n p: resourceUrlComponents?.AbsolutePath,\n q: resourceUrlComponents?.QueryString\n ? [[], resourceUrlComponents.QueryString]\n : undefined,\n client_claims: shrClaims || undefined,\n ...claims,\n },\n keyId,\n shrOptions,\n request.correlationId\n );\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ISerializableTokenCache } from \"../interface/ISerializableTokenCache\";\n\n/**\n * This class instance helps track the memory changes facilitating\n * decisions to read from and write to the persistent cache\n */ export class TokenCacheContext {\n /**\n * boolean indicating cache change\n */\n hasChanged: boolean;\n /**\n * serializable token cache interface\n */\n cache: ISerializableTokenCache;\n\n constructor(tokenCache: ISerializableTokenCache, hasChanged: boolean) {\n this.cache = tokenCache;\n this.hasChanged = hasChanged;\n }\n\n /**\n * boolean which indicates the changes in cache\n */\n get cacheHasChanged(): boolean {\n return this.hasChanged;\n }\n\n /**\n * function to retrieve the token cache\n */\n get tokenCache(): ISerializableTokenCache {\n return this.cache;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ServerAuthorizationTokenResponse } from \"./ServerAuthorizationTokenResponse\";\nimport { ICrypto } from \"../crypto/ICrypto\";\nimport {\n ClientAuthErrorCodes,\n createClientAuthError,\n} from \"../error/ClientAuthError\";\nimport { ServerAuthorizationCodeResponse } from \"./ServerAuthorizationCodeResponse\";\nimport { Logger } from \"../logger/Logger\";\nimport { ServerError } from \"../error/ServerError\";\nimport { ScopeSet } from \"../request/ScopeSet\";\nimport { AuthenticationResult } from \"./AuthenticationResult\";\nimport { AccountEntity } from \"../cache/entities/AccountEntity\";\nimport { Authority } from \"../authority/Authority\";\nimport { IdTokenEntity } from \"../cache/entities/IdTokenEntity\";\nimport { AccessTokenEntity } from \"../cache/entities/AccessTokenEntity\";\nimport { RefreshTokenEntity } from \"../cache/entities/RefreshTokenEntity\";\nimport {\n InteractionRequiredAuthError,\n isInteractionRequiredError,\n} from \"../error/InteractionRequiredAuthError\";\nimport { CacheRecord } from \"../cache/entities/CacheRecord\";\nimport { CacheManager } from \"../cache/CacheManager\";\nimport { ProtocolUtils, RequestStateObject } from \"../utils/ProtocolUtils\";\nimport {\n AuthenticationScheme,\n Constants,\n THE_FAMILY_ID,\n HttpStatus,\n} from \"../utils/Constants\";\nimport { PopTokenGenerator } from \"../crypto/PopTokenGenerator\";\nimport { AppMetadataEntity } from \"../cache/entities/AppMetadataEntity\";\nimport { ICachePlugin } from \"../cache/interface/ICachePlugin\";\nimport { TokenCacheContext } from \"../cache/persistence/TokenCacheContext\";\nimport { ISerializableTokenCache } from \"../cache/interface/ISerializableTokenCache\";\nimport { AuthorizationCodePayload } from \"./AuthorizationCodePayload\";\nimport { BaseAuthRequest } from \"../request/BaseAuthRequest\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { checkMaxAge, extractTokenClaims } from \"../account/AuthToken\";\nimport {\n TokenClaims,\n getTenantIdFromIdTokenClaims,\n} from \"../account/TokenClaims\";\nimport {\n AccountInfo,\n buildTenantProfileFromIdTokenClaims,\n updateAccountTenantProfileData,\n} from \"../account/AccountInfo\";\nimport * as CacheHelpers from \"../cache/utils/CacheHelpers\";\n\n/**\n * Class that handles response parsing.\n * @internal\n */\nexport class ResponseHandler {\n private clientId: string;\n private cacheStorage: CacheManager;\n private cryptoObj: ICrypto;\n private logger: Logger;\n private homeAccountIdentifier: string;\n private serializableCache: ISerializableTokenCache | null;\n private persistencePlugin: ICachePlugin | null;\n private performanceClient?: IPerformanceClient;\n\n constructor(\n clientId: string,\n cacheStorage: CacheManager,\n cryptoObj: ICrypto,\n logger: Logger,\n serializableCache: ISerializableTokenCache | null,\n persistencePlugin: ICachePlugin | null,\n performanceClient?: IPerformanceClient\n ) {\n this.clientId = clientId;\n this.cacheStorage = cacheStorage;\n this.cryptoObj = cryptoObj;\n this.logger = logger;\n this.serializableCache = serializableCache;\n this.persistencePlugin = persistencePlugin;\n this.performanceClient = performanceClient;\n }\n\n /**\n * Function which validates server authorization code response.\n * @param serverResponseHash\n * @param requestState\n * @param cryptoObj\n */\n validateServerAuthorizationCodeResponse(\n serverResponse: ServerAuthorizationCodeResponse,\n requestState: string\n ): void {\n if (!serverResponse.state || !requestState) {\n throw serverResponse.state\n ? createClientAuthError(\n ClientAuthErrorCodes.stateNotFound,\n \"Cached State\"\n )\n : createClientAuthError(\n ClientAuthErrorCodes.stateNotFound,\n \"Server State\"\n );\n }\n\n let decodedServerResponseState: string;\n let decodedRequestState: string;\n\n try {\n decodedServerResponseState = decodeURIComponent(\n serverResponse.state\n );\n } catch (e) {\n throw createClientAuthError(\n ClientAuthErrorCodes.invalidState,\n serverResponse.state\n );\n }\n\n try {\n decodedRequestState = decodeURIComponent(requestState);\n } catch (e) {\n throw createClientAuthError(\n ClientAuthErrorCodes.invalidState,\n serverResponse.state\n );\n }\n\n if (decodedServerResponseState !== decodedRequestState) {\n throw createClientAuthError(ClientAuthErrorCodes.stateMismatch);\n }\n\n // Check for error\n if (\n serverResponse.error ||\n serverResponse.error_description ||\n serverResponse.suberror\n ) {\n if (\n isInteractionRequiredError(\n serverResponse.error,\n serverResponse.error_description,\n serverResponse.suberror\n )\n ) {\n throw new InteractionRequiredAuthError(\n serverResponse.error || \"\",\n serverResponse.error_description,\n serverResponse.suberror,\n serverResponse.timestamp || \"\",\n serverResponse.trace_id || \"\",\n serverResponse.correlation_id || \"\",\n serverResponse.claims || \"\"\n );\n }\n\n throw new ServerError(\n serverResponse.error || \"\",\n serverResponse.error_description,\n serverResponse.suberror\n );\n }\n }\n\n /**\n * Function which validates server authorization token response.\n * @param serverResponse\n * @param refreshAccessToken\n */\n validateTokenResponse(\n serverResponse: ServerAuthorizationTokenResponse,\n refreshAccessToken?: boolean\n ): void {\n // Check for error\n if (\n serverResponse.error ||\n serverResponse.error_description ||\n serverResponse.suberror\n ) {\n const errString = `${serverResponse.error_codes} - [${serverResponse.timestamp}]: ${serverResponse.error_description} - Correlation ID: ${serverResponse.correlation_id} - Trace ID: ${serverResponse.trace_id}`;\n const serverError = new ServerError(\n serverResponse.error,\n errString,\n serverResponse.suberror\n );\n\n // check if 500 error\n if (\n refreshAccessToken &&\n serverResponse.status &&\n serverResponse.status >= HttpStatus.SERVER_ERROR_RANGE_START &&\n serverResponse.status <= HttpStatus.SERVER_ERROR_RANGE_END\n ) {\n this.logger.warning(\n `executeTokenRequest:validateTokenResponse - AAD is currently unavailable and the access token is unable to be refreshed.\\n${serverError}`\n );\n\n // don't throw an exception, but alert the user via a log that the token was unable to be refreshed\n return;\n // check if 400 error\n } else if (\n refreshAccessToken &&\n serverResponse.status &&\n serverResponse.status >= HttpStatus.CLIENT_ERROR_RANGE_START &&\n serverResponse.status <= HttpStatus.CLIENT_ERROR_RANGE_END\n ) {\n this.logger.warning(\n `executeTokenRequest:validateTokenResponse - AAD is currently available but is unable to refresh the access token.\\n${serverError}`\n );\n\n // don't throw an exception, but alert the user via a log that the token was unable to be refreshed\n return;\n }\n\n if (\n isInteractionRequiredError(\n serverResponse.error,\n serverResponse.error_description,\n serverResponse.suberror\n )\n ) {\n throw new InteractionRequiredAuthError(\n serverResponse.error,\n serverResponse.error_description,\n serverResponse.suberror,\n serverResponse.timestamp || Constants.EMPTY_STRING,\n serverResponse.trace_id || Constants.EMPTY_STRING,\n serverResponse.correlation_id || Constants.EMPTY_STRING,\n serverResponse.claims || Constants.EMPTY_STRING\n );\n }\n\n throw serverError;\n }\n }\n\n /**\n * Returns a constructed token response based on given string. Also manages the cache updates and cleanups.\n * @param serverTokenResponse\n * @param authority\n */\n async handleServerTokenResponse(\n serverTokenResponse: ServerAuthorizationTokenResponse,\n authority: Authority,\n reqTimestamp: number,\n request: BaseAuthRequest,\n authCodePayload?: AuthorizationCodePayload,\n userAssertionHash?: string,\n handlingRefreshTokenResponse?: boolean,\n forceCacheRefreshTokenResponse?: boolean,\n serverRequestId?: string\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.HandleServerTokenResponse,\n serverTokenResponse.correlation_id\n );\n\n // create an idToken object (not entity)\n let idTokenClaims: TokenClaims | undefined;\n if (serverTokenResponse.id_token) {\n idTokenClaims = extractTokenClaims(\n serverTokenResponse.id_token || Constants.EMPTY_STRING,\n this.cryptoObj.base64Decode\n );\n\n // token nonce check (TODO: Add a warning if no nonce is given?)\n if (authCodePayload && authCodePayload.nonce) {\n if (idTokenClaims.nonce !== authCodePayload.nonce) {\n throw createClientAuthError(\n ClientAuthErrorCodes.nonceMismatch\n );\n }\n }\n\n // token max_age check\n if (request.maxAge || request.maxAge === 0) {\n const authTime = idTokenClaims.auth_time;\n if (!authTime) {\n throw createClientAuthError(\n ClientAuthErrorCodes.authTimeNotFound\n );\n }\n\n checkMaxAge(authTime, request.maxAge);\n }\n }\n\n // generate homeAccountId\n this.homeAccountIdentifier = AccountEntity.generateHomeAccountId(\n serverTokenResponse.client_info || Constants.EMPTY_STRING,\n authority.authorityType,\n this.logger,\n this.cryptoObj,\n idTokenClaims\n );\n\n // save the response tokens\n let requestStateObj: RequestStateObject | undefined;\n if (!!authCodePayload && !!authCodePayload.state) {\n requestStateObj = ProtocolUtils.parseRequestState(\n this.cryptoObj,\n authCodePayload.state\n );\n }\n\n // Add keyId from request to serverTokenResponse if defined\n serverTokenResponse.key_id =\n serverTokenResponse.key_id || request.sshKid || undefined;\n\n const cacheRecord = this.generateCacheRecord(\n serverTokenResponse,\n authority,\n reqTimestamp,\n request,\n idTokenClaims,\n userAssertionHash,\n authCodePayload\n );\n let cacheContext;\n try {\n if (this.persistencePlugin && this.serializableCache) {\n this.logger.verbose(\n \"Persistence enabled, calling beforeCacheAccess\"\n );\n cacheContext = new TokenCacheContext(\n this.serializableCache,\n true\n );\n await this.persistencePlugin.beforeCacheAccess(cacheContext);\n }\n /*\n * When saving a refreshed tokens to the cache, it is expected that the account that was used is present in the cache.\n * If not present, we should return null, as it's the case that another application called removeAccount in between\n * the calls to getAllAccounts and acquireTokenSilent. We should not overwrite that removal, unless explicitly flagged by\n * the developer, as in the case of refresh token flow used in ADAL Node to MSAL Node migration.\n */\n if (\n handlingRefreshTokenResponse &&\n !forceCacheRefreshTokenResponse &&\n cacheRecord.account\n ) {\n const key = cacheRecord.account.generateAccountKey();\n const account = this.cacheStorage.getAccount(key, this.logger);\n if (!account) {\n this.logger.warning(\n \"Account used to refresh tokens not in persistence, refreshed tokens will not be stored in the cache\"\n );\n return await ResponseHandler.generateAuthenticationResult(\n this.cryptoObj,\n authority,\n cacheRecord,\n false,\n request,\n idTokenClaims,\n requestStateObj,\n undefined,\n serverRequestId\n );\n }\n }\n await this.cacheStorage.saveCacheRecord(\n cacheRecord,\n request.storeInCache\n );\n } finally {\n if (\n this.persistencePlugin &&\n this.serializableCache &&\n cacheContext\n ) {\n this.logger.verbose(\n \"Persistence enabled, calling afterCacheAccess\"\n );\n await this.persistencePlugin.afterCacheAccess(cacheContext);\n }\n }\n\n return ResponseHandler.generateAuthenticationResult(\n this.cryptoObj,\n authority,\n cacheRecord,\n false,\n request,\n idTokenClaims,\n requestStateObj,\n serverTokenResponse,\n serverRequestId\n );\n }\n\n /**\n * Generates CacheRecord\n * @param serverTokenResponse\n * @param idTokenObj\n * @param authority\n */\n private generateCacheRecord(\n serverTokenResponse: ServerAuthorizationTokenResponse,\n authority: Authority,\n reqTimestamp: number,\n request: BaseAuthRequest,\n idTokenClaims?: TokenClaims,\n userAssertionHash?: string,\n authCodePayload?: AuthorizationCodePayload\n ): CacheRecord {\n const env = authority.getPreferredCache();\n if (!env) {\n throw createClientAuthError(\n ClientAuthErrorCodes.invalidCacheEnvironment\n );\n }\n\n const claimsTenantId = getTenantIdFromIdTokenClaims(idTokenClaims);\n\n // IdToken: non AAD scenarios can have empty realm\n let cachedIdToken: IdTokenEntity | undefined;\n let cachedAccount: AccountEntity | undefined;\n if (serverTokenResponse.id_token && !!idTokenClaims) {\n cachedIdToken = CacheHelpers.createIdTokenEntity(\n this.homeAccountIdentifier,\n env,\n serverTokenResponse.id_token,\n this.clientId,\n claimsTenantId || \"\"\n );\n\n cachedAccount = buildAccountToCache(\n this.cacheStorage,\n authority,\n this.homeAccountIdentifier,\n idTokenClaims,\n this.cryptoObj.base64Decode,\n serverTokenResponse.client_info,\n env,\n claimsTenantId,\n authCodePayload,\n undefined, // nativeAccountId\n this.logger\n );\n }\n\n // AccessToken\n let cachedAccessToken: AccessTokenEntity | null = null;\n if (serverTokenResponse.access_token) {\n // If scopes not returned in server response, use request scopes\n const responseScopes = serverTokenResponse.scope\n ? ScopeSet.fromString(serverTokenResponse.scope)\n : new ScopeSet(request.scopes || []);\n\n /*\n * Use timestamp calculated before request\n * Server may return timestamps as strings, parse to numbers if so.\n */\n const expiresIn: number =\n (typeof serverTokenResponse.expires_in === \"string\"\n ? parseInt(serverTokenResponse.expires_in, 10)\n : serverTokenResponse.expires_in) || 0;\n const extExpiresIn: number =\n (typeof serverTokenResponse.ext_expires_in === \"string\"\n ? parseInt(serverTokenResponse.ext_expires_in, 10)\n : serverTokenResponse.ext_expires_in) || 0;\n const refreshIn: number | undefined =\n (typeof serverTokenResponse.refresh_in === \"string\"\n ? parseInt(serverTokenResponse.refresh_in, 10)\n : serverTokenResponse.refresh_in) || undefined;\n const tokenExpirationSeconds = reqTimestamp + expiresIn;\n const extendedTokenExpirationSeconds =\n tokenExpirationSeconds + extExpiresIn;\n const refreshOnSeconds =\n refreshIn && refreshIn > 0\n ? reqTimestamp + refreshIn\n : undefined;\n\n // non AAD scenarios can have empty realm\n cachedAccessToken = CacheHelpers.createAccessTokenEntity(\n this.homeAccountIdentifier,\n env,\n serverTokenResponse.access_token,\n this.clientId,\n claimsTenantId || authority.tenant || \"\",\n responseScopes.printScopes(),\n tokenExpirationSeconds,\n extendedTokenExpirationSeconds,\n this.cryptoObj.base64Decode,\n refreshOnSeconds,\n serverTokenResponse.token_type,\n userAssertionHash,\n serverTokenResponse.key_id,\n request.claims,\n request.requestedClaimsHash\n );\n }\n\n // refreshToken\n let cachedRefreshToken: RefreshTokenEntity | null = null;\n if (serverTokenResponse.refresh_token) {\n let rtExpiresOn: number | undefined;\n if (serverTokenResponse.refresh_token_expires_in) {\n const rtExpiresIn: number =\n typeof serverTokenResponse.refresh_token_expires_in ===\n \"string\"\n ? parseInt(\n serverTokenResponse.refresh_token_expires_in,\n 10\n )\n : serverTokenResponse.refresh_token_expires_in;\n rtExpiresOn = reqTimestamp + rtExpiresIn;\n }\n cachedRefreshToken = CacheHelpers.createRefreshTokenEntity(\n this.homeAccountIdentifier,\n env,\n serverTokenResponse.refresh_token,\n this.clientId,\n serverTokenResponse.foci,\n userAssertionHash,\n rtExpiresOn\n );\n }\n\n // appMetadata\n let cachedAppMetadata: AppMetadataEntity | null = null;\n if (serverTokenResponse.foci) {\n cachedAppMetadata = {\n clientId: this.clientId,\n environment: env,\n familyId: serverTokenResponse.foci,\n };\n }\n\n return new CacheRecord(\n cachedAccount,\n cachedIdToken,\n cachedAccessToken,\n cachedRefreshToken,\n cachedAppMetadata\n );\n }\n\n /**\n * Creates an @AuthenticationResult from @CacheRecord , @IdToken , and a boolean that states whether or not the result is from cache.\n *\n * Optionally takes a state string that is set as-is in the response.\n *\n * @param cacheRecord\n * @param idTokenObj\n * @param fromTokenCache\n * @param stateString\n */\n static async generateAuthenticationResult(\n cryptoObj: ICrypto,\n authority: Authority,\n cacheRecord: CacheRecord,\n fromTokenCache: boolean,\n request: BaseAuthRequest,\n idTokenClaims?: TokenClaims,\n requestState?: RequestStateObject,\n serverTokenResponse?: ServerAuthorizationTokenResponse,\n requestId?: string\n ): Promise {\n let accessToken: string = Constants.EMPTY_STRING;\n let responseScopes: Array = [];\n let expiresOn: Date | null = null;\n let extExpiresOn: Date | undefined;\n let refreshOn: Date | undefined;\n let familyId: string = Constants.EMPTY_STRING;\n\n if (cacheRecord.accessToken) {\n if (\n cacheRecord.accessToken.tokenType === AuthenticationScheme.POP\n ) {\n const popTokenGenerator: PopTokenGenerator =\n new PopTokenGenerator(cryptoObj);\n const { secret, keyId } = cacheRecord.accessToken;\n\n if (!keyId) {\n throw createClientAuthError(\n ClientAuthErrorCodes.keyIdMissing\n );\n }\n\n accessToken = await popTokenGenerator.signPopToken(\n secret,\n keyId,\n request\n );\n } else {\n accessToken = cacheRecord.accessToken.secret;\n }\n responseScopes = ScopeSet.fromString(\n cacheRecord.accessToken.target\n ).asArray();\n expiresOn = new Date(\n Number(cacheRecord.accessToken.expiresOn) * 1000\n );\n extExpiresOn = new Date(\n Number(cacheRecord.accessToken.extendedExpiresOn) * 1000\n );\n if (cacheRecord.accessToken.refreshOn) {\n refreshOn = new Date(\n Number(cacheRecord.accessToken.refreshOn) * 1000\n );\n }\n }\n\n if (cacheRecord.appMetadata) {\n familyId =\n cacheRecord.appMetadata.familyId === THE_FAMILY_ID\n ? THE_FAMILY_ID\n : \"\";\n }\n const uid = idTokenClaims?.oid || idTokenClaims?.sub || \"\";\n const tid = idTokenClaims?.tid || \"\";\n\n // for hybrid + native bridge enablement, send back the native account Id\n if (serverTokenResponse?.spa_accountid && !!cacheRecord.account) {\n cacheRecord.account.nativeAccountId =\n serverTokenResponse?.spa_accountid;\n }\n\n const accountInfo: AccountInfo | null = cacheRecord.account\n ? updateAccountTenantProfileData(\n cacheRecord.account.getAccountInfo(),\n undefined, // tenantProfile optional\n idTokenClaims,\n cacheRecord.idToken?.secret\n )\n : null;\n\n return {\n authority: authority.canonicalAuthority,\n uniqueId: uid,\n tenantId: tid,\n scopes: responseScopes,\n account: accountInfo,\n idToken: cacheRecord?.idToken?.secret || \"\",\n idTokenClaims: idTokenClaims || {},\n accessToken: accessToken,\n fromCache: fromTokenCache,\n expiresOn: expiresOn,\n extExpiresOn: extExpiresOn,\n refreshOn: refreshOn,\n correlationId: request.correlationId,\n requestId: requestId || Constants.EMPTY_STRING,\n familyId: familyId,\n tokenType:\n cacheRecord.accessToken?.tokenType || Constants.EMPTY_STRING,\n state: requestState\n ? requestState.userRequestState\n : Constants.EMPTY_STRING,\n cloudGraphHostName:\n cacheRecord.account?.cloudGraphHostName ||\n Constants.EMPTY_STRING,\n msGraphHost:\n cacheRecord.account?.msGraphHost || Constants.EMPTY_STRING,\n code: serverTokenResponse?.spa_code,\n fromNativeBroker: false,\n };\n }\n}\n\nexport function buildAccountToCache(\n cacheStorage: CacheManager,\n authority: Authority,\n homeAccountId: string,\n idTokenClaims: TokenClaims,\n base64Decode: (input: string) => string,\n clientInfo?: string,\n environment?: string,\n claimsTenantId?: string | null,\n authCodePayload?: AuthorizationCodePayload,\n nativeAccountId?: string,\n logger?: Logger\n): AccountEntity {\n logger?.verbose(\"setCachedAccount called\");\n\n // Check if base account is already cached\n const accountKeys = cacheStorage.getAccountKeys();\n const baseAccountKey = accountKeys.find((accountKey: string) => {\n return accountKey.startsWith(homeAccountId);\n });\n\n let cachedAccount: AccountEntity | null = null;\n if (baseAccountKey) {\n cachedAccount = cacheStorage.getAccount(baseAccountKey, logger);\n }\n\n const baseAccount =\n cachedAccount ||\n AccountEntity.createAccount(\n {\n homeAccountId,\n idTokenClaims,\n clientInfo,\n environment,\n cloudGraphHostName: authCodePayload?.cloud_graph_host_name,\n msGraphHost: authCodePayload?.msgraph_host,\n nativeAccountId: nativeAccountId,\n },\n authority,\n base64Decode\n );\n\n const tenantProfiles = baseAccount.tenantProfiles || [];\n\n if (\n claimsTenantId &&\n !tenantProfiles.find((tenantProfile) => {\n return tenantProfile.tenantId === claimsTenantId;\n })\n ) {\n const newTenantProfile = buildTenantProfileFromIdTokenClaims(\n homeAccountId,\n idTokenClaims\n );\n tenantProfiles.push(newTenantProfile);\n }\n baseAccount.tenantProfiles = tenantProfiles;\n\n return baseAccount;\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { BaseClient } from \"./BaseClient\";\nimport { CommonAuthorizationUrlRequest } from \"../request/CommonAuthorizationUrlRequest\";\nimport { CommonAuthorizationCodeRequest } from \"../request/CommonAuthorizationCodeRequest\";\nimport { Authority } from \"../authority/Authority\";\nimport { RequestParameterBuilder } from \"../request/RequestParameterBuilder\";\nimport {\n GrantType,\n AuthenticationScheme,\n PromptValue,\n Separators,\n HeaderNames,\n} from \"../utils/Constants\";\nimport * as AADServerParamKeys from \"../constants/AADServerParamKeys\";\nimport {\n ClientConfiguration,\n isOidcProtocolMode,\n} from \"../config/ClientConfiguration\";\nimport { ServerAuthorizationTokenResponse } from \"../response/ServerAuthorizationTokenResponse\";\nimport { NetworkResponse } from \"../network/NetworkManager\";\nimport { ResponseHandler } from \"../response/ResponseHandler\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport { StringUtils } from \"../utils/StringUtils\";\nimport {\n ClientAuthErrorCodes,\n createClientAuthError,\n} from \"../error/ClientAuthError\";\nimport { UrlString } from \"../url/UrlString\";\nimport { ServerAuthorizationCodeResponse } from \"../response/ServerAuthorizationCodeResponse\";\nimport { CommonEndSessionRequest } from \"../request/CommonEndSessionRequest\";\nimport { PopTokenGenerator } from \"../crypto/PopTokenGenerator\";\nimport { RequestThumbprint } from \"../network/RequestThumbprint\";\nimport { AuthorizationCodePayload } from \"../response/AuthorizationCodePayload\";\nimport * as TimeUtils from \"../utils/TimeUtils\";\nimport { AccountInfo } from \"../account/AccountInfo\";\nimport {\n buildClientInfoFromHomeAccountId,\n buildClientInfo,\n} from \"../account/ClientInfo\";\nimport { CcsCredentialType, CcsCredential } from \"../account/CcsCredential\";\nimport {\n createClientConfigurationError,\n ClientConfigurationErrorCodes,\n} from \"../error/ClientConfigurationError\";\nimport { RequestValidator } from \"../request/RequestValidator\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { invokeAsync } from \"../utils/FunctionWrappers\";\n\n/**\n * Oauth2.0 Authorization Code client\n * @internal\n */\nexport class AuthorizationCodeClient extends BaseClient {\n // Flag to indicate if client is for hybrid spa auth code redemption\n protected includeRedirectUri: boolean = true;\n private oidcDefaultScopes;\n\n constructor(\n configuration: ClientConfiguration,\n performanceClient?: IPerformanceClient\n ) {\n super(configuration, performanceClient);\n this.oidcDefaultScopes =\n this.config.authOptions.authority.options.OIDCOptions?.defaultScopes;\n }\n\n /**\n * Creates the URL of the authorization request letting the user input credentials and consent to the\n * application. The URL target the /authorize endpoint of the authority configured in the\n * application object.\n *\n * Once the user inputs their credentials and consents, the authority will send a response to the redirect URI\n * sent in the request and should contain an authorization code, which can then be used to acquire tokens via\n * acquireToken(AuthorizationCodeRequest)\n * @param request\n */\n async getAuthCodeUrl(\n request: CommonAuthorizationUrlRequest\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.GetAuthCodeUrl,\n request.correlationId\n );\n\n const queryString = await invokeAsync(\n this.createAuthCodeUrlQueryString.bind(this),\n PerformanceEvents.AuthClientCreateQueryString,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request);\n\n return UrlString.appendQueryString(\n this.authority.authorizationEndpoint,\n queryString\n );\n }\n\n /**\n * API to acquire a token in exchange of 'authorization_code` acquired by the user in the first leg of the\n * authorization_code_grant\n * @param request\n */\n async acquireToken(\n request: CommonAuthorizationCodeRequest,\n authCodePayload?: AuthorizationCodePayload\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthClientAcquireToken,\n request.correlationId\n );\n\n if (!request.code) {\n throw createClientAuthError(\n ClientAuthErrorCodes.requestCannotBeMade\n );\n }\n\n const reqTimestamp = TimeUtils.nowSeconds();\n const response = await invokeAsync(\n this.executeTokenRequest.bind(this),\n PerformanceEvents.AuthClientExecuteTokenRequest,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(this.authority, request);\n\n // Retrieve requestId from response headers\n const requestId = response.headers?.[HeaderNames.X_MS_REQUEST_ID];\n\n const responseHandler = new ResponseHandler(\n this.config.authOptions.clientId,\n this.cacheManager,\n this.cryptoUtils,\n this.logger,\n this.config.serializableCache,\n this.config.persistencePlugin,\n this.performanceClient\n );\n\n // Validate response. This function throws a server error if an error is returned by the server.\n responseHandler.validateTokenResponse(response.body);\n\n return invokeAsync(\n responseHandler.handleServerTokenResponse.bind(responseHandler),\n PerformanceEvents.HandleServerTokenResponse,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(\n response.body,\n this.authority,\n reqTimestamp,\n request,\n authCodePayload,\n undefined,\n undefined,\n undefined,\n requestId\n );\n }\n\n /**\n * Handles the hash fragment response from public client code request. Returns a code response used by\n * the client to exchange for a token in acquireToken.\n * @param hashFragment\n */\n handleFragmentResponse(\n serverParams: ServerAuthorizationCodeResponse,\n cachedState: string\n ): AuthorizationCodePayload {\n // Handle responses.\n const responseHandler = new ResponseHandler(\n this.config.authOptions.clientId,\n this.cacheManager,\n this.cryptoUtils,\n this.logger,\n null,\n null\n );\n\n // Get code response\n responseHandler.validateServerAuthorizationCodeResponse(\n serverParams,\n cachedState\n );\n\n // throw when there is no auth code in the response\n if (!serverParams.code) {\n throw createClientAuthError(\n ClientAuthErrorCodes.authorizationCodeMissingFromServerResponse\n );\n }\n\n return serverParams as AuthorizationCodePayload;\n }\n\n /**\n * Used to log out the current user, and redirect the user to the postLogoutRedirectUri.\n * Default behaviour is to redirect the user to `window.location.href`.\n * @param authorityUri\n */\n getLogoutUri(logoutRequest: CommonEndSessionRequest): string {\n // Throw error if logoutRequest is null/undefined\n if (!logoutRequest) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.logoutRequestEmpty\n );\n }\n const queryString = this.createLogoutUrlQueryString(logoutRequest);\n\n // Construct logout URI\n return UrlString.appendQueryString(\n this.authority.endSessionEndpoint,\n queryString\n );\n }\n\n /**\n * Executes POST request to token endpoint\n * @param authority\n * @param request\n */\n private async executeTokenRequest(\n authority: Authority,\n request: CommonAuthorizationCodeRequest\n ): Promise> {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthClientExecuteTokenRequest,\n request.correlationId\n );\n\n const queryParametersString = this.createTokenQueryParameters(request);\n const endpoint = UrlString.appendQueryString(\n authority.tokenEndpoint,\n queryParametersString\n );\n\n const requestBody = await invokeAsync(\n this.createTokenRequestBody.bind(this),\n PerformanceEvents.AuthClientCreateTokenRequestBody,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request);\n\n let ccsCredential: CcsCredential | undefined = undefined;\n if (request.clientInfo) {\n try {\n const clientInfo = buildClientInfo(\n request.clientInfo,\n this.cryptoUtils.base64Decode\n );\n ccsCredential = {\n credential: `${clientInfo.uid}${Separators.CLIENT_INFO_SEPARATOR}${clientInfo.utid}`,\n type: CcsCredentialType.HOME_ACCOUNT_ID,\n };\n } catch (e) {\n this.logger.verbose(\n \"Could not parse client info for CCS Header: \" + e\n );\n }\n }\n const headers: Record = this.createTokenRequestHeaders(\n ccsCredential || request.ccsCredential\n );\n\n const thumbprint: RequestThumbprint = {\n clientId:\n request.tokenBodyParameters?.clientId ||\n this.config.authOptions.clientId,\n authority: authority.canonicalAuthority,\n scopes: request.scopes,\n claims: request.claims,\n authenticationScheme: request.authenticationScheme,\n resourceRequestMethod: request.resourceRequestMethod,\n resourceRequestUri: request.resourceRequestUri,\n shrClaims: request.shrClaims,\n sshKid: request.sshKid,\n };\n\n return invokeAsync(\n this.executePostToTokenEndpoint.bind(this),\n PerformanceEvents.AuthorizationCodeClientExecutePostToTokenEndpoint,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(\n endpoint,\n requestBody,\n headers,\n thumbprint,\n request.correlationId,\n PerformanceEvents.AuthorizationCodeClientExecutePostToTokenEndpoint\n );\n }\n\n /**\n * Generates a map for all the params to be sent to the service\n * @param request\n */\n private async createTokenRequestBody(\n request: CommonAuthorizationCodeRequest\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthClientCreateTokenRequestBody,\n request.correlationId\n );\n\n const parameterBuilder = new RequestParameterBuilder();\n\n parameterBuilder.addClientId(\n request.tokenBodyParameters?.[AADServerParamKeys.CLIENT_ID] ||\n this.config.authOptions.clientId\n );\n\n /*\n * For hybrid spa flow, there will be a code but no verifier\n * In this scenario, don't include redirect uri as auth code will not be bound to redirect URI\n */\n if (!this.includeRedirectUri) {\n // Just validate\n RequestValidator.validateRedirectUri(request.redirectUri);\n } else {\n // Validate and include redirect uri\n parameterBuilder.addRedirectUri(request.redirectUri);\n }\n\n // Add scope array, parameter builder will add default scopes and dedupe\n parameterBuilder.addScopes(\n request.scopes,\n true,\n this.oidcDefaultScopes\n );\n\n // add code: user set, not validated\n parameterBuilder.addAuthorizationCode(request.code);\n\n // Add library metadata\n parameterBuilder.addLibraryInfo(this.config.libraryInfo);\n parameterBuilder.addApplicationTelemetry(\n this.config.telemetry.application\n );\n parameterBuilder.addThrottling();\n\n if (this.serverTelemetryManager && !isOidcProtocolMode(this.config)) {\n parameterBuilder.addServerTelemetry(this.serverTelemetryManager);\n }\n\n // add code_verifier if passed\n if (request.codeVerifier) {\n parameterBuilder.addCodeVerifier(request.codeVerifier);\n }\n\n if (this.config.clientCredentials.clientSecret) {\n parameterBuilder.addClientSecret(\n this.config.clientCredentials.clientSecret\n );\n }\n\n if (this.config.clientCredentials.clientAssertion) {\n const clientAssertion =\n this.config.clientCredentials.clientAssertion;\n parameterBuilder.addClientAssertion(clientAssertion.assertion);\n parameterBuilder.addClientAssertionType(\n clientAssertion.assertionType\n );\n }\n\n parameterBuilder.addGrantType(GrantType.AUTHORIZATION_CODE_GRANT);\n parameterBuilder.addClientInfo();\n\n if (request.authenticationScheme === AuthenticationScheme.POP) {\n const popTokenGenerator = new PopTokenGenerator(\n this.cryptoUtils,\n this.performanceClient\n );\n\n const reqCnfData = await invokeAsync(\n popTokenGenerator.generateCnf.bind(popTokenGenerator),\n PerformanceEvents.PopTokenGenerateCnf,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, this.logger);\n // SPA PoP requires full Base64Url encoded req_cnf string (unhashed)\n parameterBuilder.addPopToken(reqCnfData.reqCnfString);\n } else if (request.authenticationScheme === AuthenticationScheme.SSH) {\n if (request.sshJwk) {\n parameterBuilder.addSshJwk(request.sshJwk);\n } else {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.missingSshJwk\n );\n }\n }\n\n const correlationId =\n request.correlationId ||\n this.config.cryptoInterface.createNewGuid();\n parameterBuilder.addCorrelationId(correlationId);\n\n if (\n !StringUtils.isEmptyObj(request.claims) ||\n (this.config.authOptions.clientCapabilities &&\n this.config.authOptions.clientCapabilities.length > 0)\n ) {\n parameterBuilder.addClaims(\n request.claims,\n this.config.authOptions.clientCapabilities\n );\n }\n\n let ccsCred: CcsCredential | undefined = undefined;\n if (request.clientInfo) {\n try {\n const clientInfo = buildClientInfo(\n request.clientInfo,\n this.cryptoUtils.base64Decode\n );\n ccsCred = {\n credential: `${clientInfo.uid}${Separators.CLIENT_INFO_SEPARATOR}${clientInfo.utid}`,\n type: CcsCredentialType.HOME_ACCOUNT_ID,\n };\n } catch (e) {\n this.logger.verbose(\n \"Could not parse client info for CCS Header: \" + e\n );\n }\n } else {\n ccsCred = request.ccsCredential;\n }\n\n // Adds these as parameters in the request instead of headers to prevent CORS preflight request\n if (this.config.systemOptions.preventCorsPreflight && ccsCred) {\n switch (ccsCred.type) {\n case CcsCredentialType.HOME_ACCOUNT_ID:\n try {\n const clientInfo = buildClientInfoFromHomeAccountId(\n ccsCred.credential\n );\n parameterBuilder.addCcsOid(clientInfo);\n } catch (e) {\n this.logger.verbose(\n \"Could not parse home account ID for CCS Header: \" +\n e\n );\n }\n break;\n case CcsCredentialType.UPN:\n parameterBuilder.addCcsUpn(ccsCred.credential);\n break;\n }\n }\n\n if (request.tokenBodyParameters) {\n parameterBuilder.addExtraQueryParameters(\n request.tokenBodyParameters\n );\n }\n\n // Add hybrid spa parameters if not already provided\n if (\n request.enableSpaAuthorizationCode &&\n (!request.tokenBodyParameters ||\n !request.tokenBodyParameters[\n AADServerParamKeys.RETURN_SPA_CODE\n ])\n ) {\n parameterBuilder.addExtraQueryParameters({\n [AADServerParamKeys.RETURN_SPA_CODE]: \"1\",\n });\n }\n\n return parameterBuilder.createQueryString();\n }\n\n /**\n * This API validates the `AuthorizationCodeUrlRequest` and creates a URL\n * @param request\n */\n private async createAuthCodeUrlQueryString(\n request: CommonAuthorizationUrlRequest\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.AuthClientCreateQueryString,\n request.correlationId\n );\n\n const parameterBuilder = new RequestParameterBuilder();\n\n parameterBuilder.addClientId(\n request.extraQueryParameters?.[AADServerParamKeys.CLIENT_ID] ||\n this.config.authOptions.clientId\n );\n\n const requestScopes = [\n ...(request.scopes || []),\n ...(request.extraScopesToConsent || []),\n ];\n parameterBuilder.addScopes(requestScopes, true, this.oidcDefaultScopes);\n\n // validate the redirectUri (to be a non null value)\n parameterBuilder.addRedirectUri(request.redirectUri);\n\n // generate the correlationId if not set by the user and add\n const correlationId =\n request.correlationId ||\n this.config.cryptoInterface.createNewGuid();\n parameterBuilder.addCorrelationId(correlationId);\n\n // add response_mode. If not passed in it defaults to query.\n parameterBuilder.addResponseMode(request.responseMode);\n\n // add response_type = code\n parameterBuilder.addResponseTypeCode();\n\n // add library info parameters\n parameterBuilder.addLibraryInfo(this.config.libraryInfo);\n if (!isOidcProtocolMode(this.config)) {\n parameterBuilder.addApplicationTelemetry(\n this.config.telemetry.application\n );\n }\n\n // add client_info=1\n parameterBuilder.addClientInfo();\n\n if (request.codeChallenge && request.codeChallengeMethod) {\n parameterBuilder.addCodeChallengeParams(\n request.codeChallenge,\n request.codeChallengeMethod\n );\n }\n\n if (request.prompt) {\n parameterBuilder.addPrompt(request.prompt);\n }\n\n if (request.domainHint) {\n parameterBuilder.addDomainHint(request.domainHint);\n }\n\n // Add sid or loginHint with preference for login_hint claim (in request) -> sid -> loginHint (upn/email) -> username of AccountInfo object\n if (request.prompt !== PromptValue.SELECT_ACCOUNT) {\n // AAD will throw if prompt=select_account is passed with an account hint\n if (request.sid && request.prompt === PromptValue.NONE) {\n // SessionID is only used in silent calls\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Prompt is none, adding sid from request\"\n );\n parameterBuilder.addSid(request.sid);\n } else if (request.account) {\n const accountSid = this.extractAccountSid(request.account);\n const accountLoginHintClaim = this.extractLoginHint(\n request.account\n );\n // If login_hint claim is present, use it over sid/username\n if (accountLoginHintClaim) {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: login_hint claim present on account\"\n );\n parameterBuilder.addLoginHint(accountLoginHintClaim);\n try {\n const clientInfo = buildClientInfoFromHomeAccountId(\n request.account.homeAccountId\n );\n parameterBuilder.addCcsOid(clientInfo);\n } catch (e) {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Could not parse home account ID for CCS Header\"\n );\n }\n } else if (accountSid && request.prompt === PromptValue.NONE) {\n /*\n * If account and loginHint are provided, we will check account first for sid before adding loginHint\n * SessionId is only used in silent calls\n */\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Prompt is none, adding sid from account\"\n );\n parameterBuilder.addSid(accountSid);\n try {\n const clientInfo = buildClientInfoFromHomeAccountId(\n request.account.homeAccountId\n );\n parameterBuilder.addCcsOid(clientInfo);\n } catch (e) {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Could not parse home account ID for CCS Header\"\n );\n }\n } else if (request.loginHint) {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Adding login_hint from request\"\n );\n parameterBuilder.addLoginHint(request.loginHint);\n parameterBuilder.addCcsUpn(request.loginHint);\n } else if (request.account.username) {\n // Fallback to account username if provided\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Adding login_hint from account\"\n );\n parameterBuilder.addLoginHint(request.account.username);\n try {\n const clientInfo = buildClientInfoFromHomeAccountId(\n request.account.homeAccountId\n );\n parameterBuilder.addCcsOid(clientInfo);\n } catch (e) {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Could not parse home account ID for CCS Header\"\n );\n }\n }\n } else if (request.loginHint) {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: No account, adding login_hint from request\"\n );\n parameterBuilder.addLoginHint(request.loginHint);\n parameterBuilder.addCcsUpn(request.loginHint);\n }\n } else {\n this.logger.verbose(\n \"createAuthCodeUrlQueryString: Prompt is select_account, ignoring account hints\"\n );\n }\n\n if (request.nonce) {\n parameterBuilder.addNonce(request.nonce);\n }\n\n if (request.state) {\n parameterBuilder.addState(request.state);\n }\n\n if (\n request.claims ||\n (this.config.authOptions.clientCapabilities &&\n this.config.authOptions.clientCapabilities.length > 0)\n ) {\n parameterBuilder.addClaims(\n request.claims,\n this.config.authOptions.clientCapabilities\n );\n }\n\n if (request.extraQueryParameters) {\n parameterBuilder.addExtraQueryParameters(\n request.extraQueryParameters\n );\n }\n\n if (request.nativeBroker) {\n // signal ests that this is a WAM call\n parameterBuilder.addNativeBroker();\n\n // pass the req_cnf for POP\n if (request.authenticationScheme === AuthenticationScheme.POP) {\n const popTokenGenerator = new PopTokenGenerator(\n this.cryptoUtils\n );\n // to reduce the URL length, it is recommended to send the hash of the req_cnf instead of the whole string\n const reqCnfData = await invokeAsync(\n popTokenGenerator.generateCnf.bind(popTokenGenerator),\n PerformanceEvents.PopTokenGenerateCnf,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, this.logger);\n parameterBuilder.addPopToken(reqCnfData.reqCnfHash);\n }\n }\n\n return parameterBuilder.createQueryString();\n }\n\n /**\n * This API validates the `EndSessionRequest` and creates a URL\n * @param request\n */\n private createLogoutUrlQueryString(\n request: CommonEndSessionRequest\n ): string {\n const parameterBuilder = new RequestParameterBuilder();\n\n if (request.postLogoutRedirectUri) {\n parameterBuilder.addPostLogoutRedirectUri(\n request.postLogoutRedirectUri\n );\n }\n\n if (request.correlationId) {\n parameterBuilder.addCorrelationId(request.correlationId);\n }\n\n if (request.idTokenHint) {\n parameterBuilder.addIdTokenHint(request.idTokenHint);\n }\n\n if (request.state) {\n parameterBuilder.addState(request.state);\n }\n\n if (request.logoutHint) {\n parameterBuilder.addLogoutHint(request.logoutHint);\n }\n\n if (request.extraQueryParameters) {\n parameterBuilder.addExtraQueryParameters(\n request.extraQueryParameters\n );\n }\n\n return parameterBuilder.createQueryString();\n }\n\n /**\n * Helper to get sid from account. Returns null if idTokenClaims are not present or sid is not present.\n * @param account\n */\n private extractAccountSid(account: AccountInfo): string | null {\n return account.idTokenClaims?.sid || null;\n }\n\n private extractLoginHint(account: AccountInfo): string | null {\n return account.idTokenClaims?.login_hint || null;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n SERVER_TELEM_CONSTANTS,\n Separators,\n CacheOutcome,\n Constants,\n RegionDiscoverySources,\n RegionDiscoveryOutcomes,\n} from \"../../utils/Constants\";\nimport { CacheManager } from \"../../cache/CacheManager\";\nimport { AuthError } from \"../../error/AuthError\";\nimport { ServerTelemetryRequest } from \"./ServerTelemetryRequest\";\nimport { ServerTelemetryEntity } from \"../../cache/entities/ServerTelemetryEntity\";\nimport { RegionDiscoveryMetadata } from \"../../authority/RegionDiscoveryMetadata\";\n\n/** @internal */\nexport class ServerTelemetryManager {\n private cacheManager: CacheManager;\n private apiId: number;\n private correlationId: string;\n private telemetryCacheKey: string;\n private wrapperSKU: String;\n private wrapperVer: String;\n private regionUsed: string | undefined;\n private regionSource: RegionDiscoverySources | undefined;\n private regionOutcome: RegionDiscoveryOutcomes | undefined;\n private cacheOutcome: CacheOutcome = CacheOutcome.NOT_APPLICABLE;\n\n constructor(\n telemetryRequest: ServerTelemetryRequest,\n cacheManager: CacheManager\n ) {\n this.cacheManager = cacheManager;\n this.apiId = telemetryRequest.apiId;\n this.correlationId = telemetryRequest.correlationId;\n this.wrapperSKU = telemetryRequest.wrapperSKU || Constants.EMPTY_STRING;\n this.wrapperVer = telemetryRequest.wrapperVer || Constants.EMPTY_STRING;\n\n this.telemetryCacheKey =\n SERVER_TELEM_CONSTANTS.CACHE_KEY +\n Separators.CACHE_KEY_SEPARATOR +\n telemetryRequest.clientId;\n }\n\n /**\n * API to add MSER Telemetry to request\n */\n generateCurrentRequestHeaderValue(): string {\n const request = `${this.apiId}${SERVER_TELEM_CONSTANTS.VALUE_SEPARATOR}${this.cacheOutcome}`;\n const platformFields = [this.wrapperSKU, this.wrapperVer].join(\n SERVER_TELEM_CONSTANTS.VALUE_SEPARATOR\n );\n const regionDiscoveryFields = this.getRegionDiscoveryFields();\n const requestWithRegionDiscoveryFields = [\n request,\n regionDiscoveryFields,\n ].join(SERVER_TELEM_CONSTANTS.VALUE_SEPARATOR);\n\n return [\n SERVER_TELEM_CONSTANTS.SCHEMA_VERSION,\n requestWithRegionDiscoveryFields,\n platformFields,\n ].join(SERVER_TELEM_CONSTANTS.CATEGORY_SEPARATOR);\n }\n\n /**\n * API to add MSER Telemetry for the last failed request\n */\n generateLastRequestHeaderValue(): string {\n const lastRequests = this.getLastRequests();\n\n const maxErrors = ServerTelemetryManager.maxErrorsToSend(lastRequests);\n const failedRequests = lastRequests.failedRequests\n .slice(0, 2 * maxErrors)\n .join(SERVER_TELEM_CONSTANTS.VALUE_SEPARATOR);\n const errors = lastRequests.errors\n .slice(0, maxErrors)\n .join(SERVER_TELEM_CONSTANTS.VALUE_SEPARATOR);\n const errorCount = lastRequests.errors.length;\n\n // Indicate whether this header contains all data or partial data\n const overflow =\n maxErrors < errorCount\n ? SERVER_TELEM_CONSTANTS.OVERFLOW_TRUE\n : SERVER_TELEM_CONSTANTS.OVERFLOW_FALSE;\n const platformFields = [errorCount, overflow].join(\n SERVER_TELEM_CONSTANTS.VALUE_SEPARATOR\n );\n\n return [\n SERVER_TELEM_CONSTANTS.SCHEMA_VERSION,\n lastRequests.cacheHits,\n failedRequests,\n errors,\n platformFields,\n ].join(SERVER_TELEM_CONSTANTS.CATEGORY_SEPARATOR);\n }\n\n /**\n * API to cache token failures for MSER data capture\n * @param error\n */\n cacheFailedRequest(error: unknown): void {\n const lastRequests = this.getLastRequests();\n if (\n lastRequests.errors.length >=\n SERVER_TELEM_CONSTANTS.MAX_CACHED_ERRORS\n ) {\n // Remove a cached error to make room, first in first out\n lastRequests.failedRequests.shift(); // apiId\n lastRequests.failedRequests.shift(); // correlationId\n lastRequests.errors.shift();\n }\n\n lastRequests.failedRequests.push(this.apiId, this.correlationId);\n\n if (error instanceof Error && !!error && error.toString()) {\n if (error instanceof AuthError) {\n if (error.subError) {\n lastRequests.errors.push(error.subError);\n } else if (error.errorCode) {\n lastRequests.errors.push(error.errorCode);\n } else {\n lastRequests.errors.push(error.toString());\n }\n } else {\n lastRequests.errors.push(error.toString());\n }\n } else {\n lastRequests.errors.push(SERVER_TELEM_CONSTANTS.UNKNOWN_ERROR);\n }\n\n this.cacheManager.setServerTelemetry(\n this.telemetryCacheKey,\n lastRequests\n );\n\n return;\n }\n\n /**\n * Update server telemetry cache entry by incrementing cache hit counter\n */\n incrementCacheHits(): number {\n const lastRequests = this.getLastRequests();\n lastRequests.cacheHits += 1;\n\n this.cacheManager.setServerTelemetry(\n this.telemetryCacheKey,\n lastRequests\n );\n return lastRequests.cacheHits;\n }\n\n /**\n * Get the server telemetry entity from cache or initialize a new one\n */\n getLastRequests(): ServerTelemetryEntity {\n const initialValue: ServerTelemetryEntity = {\n failedRequests: [],\n errors: [],\n cacheHits: 0,\n };\n const lastRequests = this.cacheManager.getServerTelemetry(\n this.telemetryCacheKey\n ) as ServerTelemetryEntity;\n\n return lastRequests || initialValue;\n }\n\n /**\n * Remove server telemetry cache entry\n */\n clearTelemetryCache(): void {\n const lastRequests = this.getLastRequests();\n const numErrorsFlushed =\n ServerTelemetryManager.maxErrorsToSend(lastRequests);\n const errorCount = lastRequests.errors.length;\n if (numErrorsFlushed === errorCount) {\n // All errors were sent on last request, clear Telemetry cache\n this.cacheManager.removeItem(this.telemetryCacheKey);\n } else {\n // Partial data was flushed to server, construct a new telemetry cache item with errors that were not flushed\n const serverTelemEntity: ServerTelemetryEntity = {\n failedRequests: lastRequests.failedRequests.slice(\n numErrorsFlushed * 2\n ), // failedRequests contains 2 items for each error\n errors: lastRequests.errors.slice(numErrorsFlushed),\n cacheHits: 0,\n };\n\n this.cacheManager.setServerTelemetry(\n this.telemetryCacheKey,\n serverTelemEntity\n );\n }\n }\n\n /**\n * Returns the maximum number of errors that can be flushed to the server in the next network request\n * @param serverTelemetryEntity\n */\n static maxErrorsToSend(\n serverTelemetryEntity: ServerTelemetryEntity\n ): number {\n let i;\n let maxErrors = 0;\n let dataSize = 0;\n const errorCount = serverTelemetryEntity.errors.length;\n for (i = 0; i < errorCount; i++) {\n // failedRequests parameter contains pairs of apiId and correlationId, multiply index by 2 to preserve pairs\n const apiId =\n serverTelemetryEntity.failedRequests[2 * i] ||\n Constants.EMPTY_STRING;\n const correlationId =\n serverTelemetryEntity.failedRequests[2 * i + 1] ||\n Constants.EMPTY_STRING;\n const errorCode =\n serverTelemetryEntity.errors[i] || Constants.EMPTY_STRING;\n\n // Count number of characters that would be added to header, each character is 1 byte. Add 3 at the end to account for separators\n dataSize +=\n apiId.toString().length +\n correlationId.toString().length +\n errorCode.length +\n 3;\n\n if (dataSize < SERVER_TELEM_CONSTANTS.MAX_LAST_HEADER_BYTES) {\n // Adding this entry to the header would still keep header size below the limit\n maxErrors += 1;\n } else {\n break;\n }\n }\n\n return maxErrors;\n }\n\n /**\n * Get the region discovery fields\n *\n * @returns string\n */\n getRegionDiscoveryFields(): string {\n const regionDiscoveryFields: string[] = [];\n\n regionDiscoveryFields.push(this.regionUsed || Constants.EMPTY_STRING);\n regionDiscoveryFields.push(this.regionSource || Constants.EMPTY_STRING);\n regionDiscoveryFields.push(\n this.regionOutcome || Constants.EMPTY_STRING\n );\n\n return regionDiscoveryFields.join(\",\");\n }\n\n /**\n * Update the region discovery metadata\n *\n * @param regionDiscoveryMetadata\n * @returns void\n */\n updateRegionDiscoveryMetadata(\n regionDiscoveryMetadata: RegionDiscoveryMetadata\n ): void {\n this.regionUsed = regionDiscoveryMetadata.region_used;\n this.regionSource = regionDiscoveryMetadata.region_source;\n this.regionOutcome = regionDiscoveryMetadata.region_outcome;\n }\n\n /**\n * Set cache outcome\n */\n setCacheOutcome(cacheOutcome: CacheOutcome): void {\n this.cacheOutcome = cacheOutcome;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n ICrypto,\n INetworkModule,\n Logger,\n AccountInfo,\n AccountEntity,\n BaseAuthRequest,\n AuthenticationScheme,\n UrlString,\n ServerTelemetryManager,\n ServerTelemetryRequest,\n createClientConfigurationError,\n ClientConfigurationErrorCodes,\n Authority,\n AuthorityOptions,\n AuthorityFactory,\n IPerformanceClient,\n PerformanceEvents,\n StringUtils,\n AzureCloudOptions,\n invokeAsync,\n} from \"@azure/msal-common\";\nimport { BrowserConfiguration } from \"../config/Configuration\";\nimport { BrowserCacheManager } from \"../cache/BrowserCacheManager\";\nimport { EventHandler } from \"../event/EventHandler\";\nimport { EndSessionRequest } from \"../request/EndSessionRequest\";\nimport { RedirectRequest } from \"../request/RedirectRequest\";\nimport { PopupRequest } from \"../request/PopupRequest\";\nimport { SsoSilentRequest } from \"../request/SsoSilentRequest\";\nimport { version } from \"../packageMetadata\";\nimport { BrowserConstants } from \"../utils/BrowserConstants\";\nimport * as BrowserUtils from \"../utils/BrowserUtils\";\nimport { INavigationClient } from \"../navigation/INavigationClient\";\nimport { NativeMessageHandler } from \"../broker/nativeBroker/NativeMessageHandler\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport { ClearCacheRequest } from \"../request/ClearCacheRequest\";\nimport { createNewGuid } from \"../crypto/BrowserCrypto\";\n\nexport abstract class BaseInteractionClient {\n protected config: BrowserConfiguration;\n protected browserStorage: BrowserCacheManager;\n protected browserCrypto: ICrypto;\n protected networkClient: INetworkModule;\n protected logger: Logger;\n protected eventHandler: EventHandler;\n protected navigationClient: INavigationClient;\n protected nativeMessageHandler: NativeMessageHandler | undefined;\n protected correlationId: string;\n protected performanceClient: IPerformanceClient;\n\n constructor(\n config: BrowserConfiguration,\n storageImpl: BrowserCacheManager,\n browserCrypto: ICrypto,\n logger: Logger,\n eventHandler: EventHandler,\n navigationClient: INavigationClient,\n performanceClient: IPerformanceClient,\n nativeMessageHandler?: NativeMessageHandler,\n correlationId?: string\n ) {\n this.config = config;\n this.browserStorage = storageImpl;\n this.browserCrypto = browserCrypto;\n this.networkClient = this.config.system.networkClient;\n this.eventHandler = eventHandler;\n this.navigationClient = navigationClient;\n this.nativeMessageHandler = nativeMessageHandler;\n this.correlationId = correlationId || createNewGuid();\n this.logger = logger.clone(\n BrowserConstants.MSAL_SKU,\n version,\n this.correlationId\n );\n this.performanceClient = performanceClient;\n }\n\n abstract acquireToken(\n request: RedirectRequest | PopupRequest | SsoSilentRequest\n ): Promise;\n\n abstract logout(\n request: EndSessionRequest | ClearCacheRequest | undefined\n ): Promise;\n\n protected async clearCacheOnLogout(\n account?: AccountInfo | null\n ): Promise {\n if (account) {\n if (\n AccountEntity.accountInfoIsEqual(\n account,\n this.browserStorage.getActiveAccount(),\n false\n )\n ) {\n this.logger.verbose(\"Setting active account to null\");\n this.browserStorage.setActiveAccount(null);\n }\n // Clear given account.\n try {\n await this.browserStorage.removeAccount(\n AccountEntity.generateAccountCacheKey(account)\n );\n this.logger.verbose(\n \"Cleared cache items belonging to the account provided in the logout request.\"\n );\n } catch (error) {\n this.logger.error(\n \"Account provided in logout request was not found. Local cache unchanged.\"\n );\n }\n } else {\n try {\n this.logger.verbose(\n \"No account provided in logout request, clearing all cache items.\",\n this.correlationId\n );\n // Clear all accounts and tokens\n await this.browserStorage.clear();\n // Clear any stray keys from IndexedDB\n await this.browserCrypto.clearKeystore();\n } catch (e) {\n this.logger.error(\n \"Attempted to clear all MSAL cache items and failed. Local cache unchanged.\"\n );\n }\n }\n }\n\n /**\n * Initializer function for all request APIs\n * @param request\n */\n protected async initializeBaseRequest(\n request: Partial\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.InitializeBaseRequest,\n this.correlationId\n );\n const authority = request.authority || this.config.auth.authority;\n\n const scopes = [...((request && request.scopes) || [])];\n\n const validatedRequest: BaseAuthRequest = {\n ...request,\n correlationId: this.correlationId,\n authority,\n scopes,\n };\n\n // Set authenticationScheme to BEARER if not explicitly set in the request\n if (!validatedRequest.authenticationScheme) {\n validatedRequest.authenticationScheme = AuthenticationScheme.BEARER;\n this.logger.verbose(\n 'Authentication Scheme wasn\\'t explicitly set in request, defaulting to \"Bearer\" request'\n );\n } else {\n if (\n validatedRequest.authenticationScheme ===\n AuthenticationScheme.SSH\n ) {\n if (!request.sshJwk) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.missingSshJwk\n );\n }\n if (!request.sshKid) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.missingSshKid\n );\n }\n }\n this.logger.verbose(\n `Authentication Scheme set to \"${validatedRequest.authenticationScheme}\" as configured in Auth request`\n );\n }\n\n // Set requested claims hash if claims-based caching is enabled and claims were requested\n if (\n this.config.cache.claimsBasedCachingEnabled &&\n request.claims &&\n // Checks for empty stringified object \"{}\" which doesn't qualify as requested claims\n !StringUtils.isEmptyObj(request.claims)\n ) {\n validatedRequest.requestedClaimsHash =\n await this.browserCrypto.hashString(request.claims);\n }\n\n return validatedRequest;\n }\n\n /**\n *\n * Use to get the redirect uri configured in MSAL or null.\n * @param requestRedirectUri\n * @returns Redirect URL\n *\n */\n getRedirectUri(requestRedirectUri?: string): string {\n this.logger.verbose(\"getRedirectUri called\");\n const redirectUri =\n requestRedirectUri ||\n this.config.auth.redirectUri ||\n BrowserUtils.getCurrentUri();\n return UrlString.getAbsoluteUrl(\n redirectUri,\n BrowserUtils.getCurrentUri()\n );\n }\n\n /**\n *\n * @param apiId\n * @param correlationId\n * @param forceRefresh\n */\n protected initializeServerTelemetryManager(\n apiId: number,\n forceRefresh?: boolean\n ): ServerTelemetryManager {\n this.logger.verbose(\"initializeServerTelemetryManager called\");\n const telemetryPayload: ServerTelemetryRequest = {\n clientId: this.config.auth.clientId,\n correlationId: this.correlationId,\n apiId: apiId,\n forceRefresh: forceRefresh || false,\n wrapperSKU: this.browserStorage.getWrapperMetadata()[0],\n wrapperVer: this.browserStorage.getWrapperMetadata()[1],\n };\n\n return new ServerTelemetryManager(\n telemetryPayload,\n this.browserStorage\n );\n }\n\n /**\n * Used to get a discovered version of the default authority.\n * @param requestAuthority\n * @param requestAzureCloudOptions\n * @param account\n */\n protected async getDiscoveredAuthority(\n requestAuthority?: string,\n requestAzureCloudOptions?: AzureCloudOptions,\n account?: AccountInfo\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority,\n this.correlationId\n );\n const authorityOptions: AuthorityOptions = {\n protocolMode: this.config.auth.protocolMode,\n OIDCOptions: this.config.auth.OIDCOptions,\n knownAuthorities: this.config.auth.knownAuthorities,\n cloudDiscoveryMetadata: this.config.auth.cloudDiscoveryMetadata,\n authorityMetadata: this.config.auth.authorityMetadata,\n skipAuthorityMetadataCache:\n this.config.auth.skipAuthorityMetadataCache,\n };\n\n // build authority string based on auth params, precedence - azureCloudInstance + tenant >> authority\n const userAuthority = requestAuthority\n ? requestAuthority\n : this.config.auth.authority;\n\n // fall back to the authority from config\n const builtAuthority = Authority.generateAuthority(\n userAuthority,\n requestAzureCloudOptions || this.config.auth.azureCloudOptions\n );\n const discoveredAuthority = await invokeAsync(\n AuthorityFactory.createDiscoveredInstance,\n PerformanceEvents.AuthorityFactoryCreateDiscoveredInstance,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(\n builtAuthority,\n this.config.system.networkClient,\n this.browserStorage,\n authorityOptions,\n this.logger,\n this.correlationId,\n this.performanceClient\n );\n\n if (account && !discoveredAuthority.isAlias(account.environment)) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.authorityMismatch\n );\n }\n\n return discoveredAuthority;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n IPerformanceClient,\n Logger,\n PerformanceEvents,\n PkceCodes,\n invoke,\n invokeAsync,\n} from \"@azure/msal-common\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../error/BrowserAuthError\";\nimport { urlEncodeArr } from \"../encode/Base64Encode\";\nimport { getRandomValues, sha256Digest } from \"./BrowserCrypto\";\n\n// Constant byte array length\nconst RANDOM_BYTE_ARR_LENGTH = 32;\n\n/**\n * This file defines APIs to generate PKCE codes and code verifiers.\n */\n\n/**\n * Generates PKCE Codes. See the RFC for more information: https://tools.ietf.org/html/rfc7636\n */\nexport async function generatePkceCodes(\n performanceClient: IPerformanceClient,\n logger: Logger,\n correlationId: string\n): Promise {\n performanceClient.addQueueMeasurement(\n PerformanceEvents.GeneratePkceCodes,\n correlationId\n );\n const codeVerifier = invoke(\n generateCodeVerifier,\n PerformanceEvents.GenerateCodeVerifier,\n logger,\n performanceClient,\n correlationId\n )(performanceClient, logger, correlationId);\n const codeChallenge = await invokeAsync(\n generateCodeChallengeFromVerifier,\n PerformanceEvents.GenerateCodeChallengeFromVerifier,\n logger,\n performanceClient,\n correlationId\n )(codeVerifier, performanceClient, logger, correlationId);\n return {\n verifier: codeVerifier,\n challenge: codeChallenge,\n };\n}\n\n/**\n * Generates a random 32 byte buffer and returns the base64\n * encoded string to be used as a PKCE Code Verifier\n */\nfunction generateCodeVerifier(\n performanceClient: IPerformanceClient,\n logger: Logger,\n correlationId: string\n): string {\n try {\n // Generate random values as utf-8\n const buffer: Uint8Array = new Uint8Array(RANDOM_BYTE_ARR_LENGTH);\n invoke(\n getRandomValues,\n PerformanceEvents.GetRandomValues,\n logger,\n performanceClient,\n correlationId\n )(buffer);\n // encode verifier as base64\n const pkceCodeVerifierB64: string = urlEncodeArr(buffer);\n return pkceCodeVerifierB64;\n } catch (e) {\n throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);\n }\n}\n\n/**\n * Creates a base64 encoded PKCE Code Challenge string from the\n * hash created from the PKCE Code Verifier supplied\n */\nasync function generateCodeChallengeFromVerifier(\n pkceCodeVerifier: string,\n performanceClient: IPerformanceClient,\n logger: Logger,\n correlationId: string\n): Promise {\n performanceClient.addQueueMeasurement(\n PerformanceEvents.GenerateCodeChallengeFromVerifier,\n correlationId\n );\n try {\n // hashed verifier\n const pkceHashedCodeVerifier = await invokeAsync(\n sha256Digest,\n PerformanceEvents.Sha256Digest,\n logger,\n performanceClient,\n correlationId\n )(pkceCodeVerifier, performanceClient, correlationId);\n // encode hash as base64\n return urlEncodeArr(new Uint8Array(pkceHashedCodeVerifier));\n } catch (e) {\n throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n ServerTelemetryManager,\n CommonAuthorizationCodeRequest,\n Constants,\n AuthorizationCodeClient,\n ClientConfiguration,\n UrlString,\n CommonEndSessionRequest,\n ProtocolUtils,\n ResponseMode,\n IdTokenClaims,\n AccountInfo,\n AzureCloudOptions,\n PerformanceEvents,\n invokeAsync,\n BaseAuthRequest,\n} from \"@azure/msal-common\";\nimport { BaseInteractionClient } from \"./BaseInteractionClient\";\nimport { AuthorizationUrlRequest } from \"../request/AuthorizationUrlRequest\";\nimport { BrowserConstants, InteractionType } from \"../utils/BrowserConstants\";\nimport { version } from \"../packageMetadata\";\nimport { BrowserStateObject } from \"../utils/BrowserProtocolUtils\";\nimport { EndSessionRequest } from \"../request/EndSessionRequest\";\nimport * as BrowserUtils from \"../utils/BrowserUtils\";\nimport { RedirectRequest } from \"../request/RedirectRequest\";\nimport { PopupRequest } from \"../request/PopupRequest\";\nimport { SsoSilentRequest } from \"../request/SsoSilentRequest\";\nimport { generatePkceCodes } from \"../crypto/PkceGenerator\";\nimport { createNewGuid } from \"../crypto/BrowserCrypto\";\n\n/**\n * Defines the class structure and helper functions used by the \"standard\", non-brokered auth flows (popup, redirect, silent (RT), silent (iframe))\n */\nexport abstract class StandardInteractionClient extends BaseInteractionClient {\n /**\n * Generates an auth code request tied to the url request.\n * @param request\n */\n protected async initializeAuthorizationCodeRequest(\n request: AuthorizationUrlRequest\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.StandardInteractionClientInitializeAuthorizationCodeRequest,\n this.correlationId\n );\n const generatedPkceParams = await invokeAsync(\n generatePkceCodes,\n PerformanceEvents.GeneratePkceCodes,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(this.performanceClient, this.logger, this.correlationId);\n\n const authCodeRequest: CommonAuthorizationCodeRequest = {\n ...request,\n redirectUri: request.redirectUri,\n code: Constants.EMPTY_STRING,\n codeVerifier: generatedPkceParams.verifier,\n };\n\n request.codeChallenge = generatedPkceParams.challenge;\n request.codeChallengeMethod = Constants.S256_CODE_CHALLENGE_METHOD;\n\n return authCodeRequest;\n }\n\n /**\n * Initializer for the logout request.\n * @param logoutRequest\n */\n protected initializeLogoutRequest(\n logoutRequest?: EndSessionRequest\n ): CommonEndSessionRequest {\n this.logger.verbose(\n \"initializeLogoutRequest called\",\n logoutRequest?.correlationId\n );\n\n const validLogoutRequest: CommonEndSessionRequest = {\n correlationId: this.correlationId || createNewGuid(),\n ...logoutRequest,\n };\n\n /**\n * Set logout_hint to be login_hint from ID Token Claims if present\n * and logoutHint attribute wasn't manually set in logout request\n */\n if (logoutRequest) {\n // If logoutHint isn't set and an account was passed in, try to extract logoutHint from ID Token Claims\n if (!logoutRequest.logoutHint) {\n if (logoutRequest.account) {\n const logoutHint = this.getLogoutHintFromIdTokenClaims(\n logoutRequest.account\n );\n if (logoutHint) {\n this.logger.verbose(\n \"Setting logoutHint to login_hint ID Token Claim value for the account provided\"\n );\n validLogoutRequest.logoutHint = logoutHint;\n }\n } else {\n this.logger.verbose(\n \"logoutHint was not set and account was not passed into logout request, logoutHint will not be set\"\n );\n }\n } else {\n this.logger.verbose(\n \"logoutHint has already been set in logoutRequest\"\n );\n }\n } else {\n this.logger.verbose(\n \"logoutHint will not be set since no logout request was configured\"\n );\n }\n\n /*\n * Only set redirect uri if logout request isn't provided or the set uri isn't null.\n * Otherwise, use passed uri, config, or current page.\n */\n if (!logoutRequest || logoutRequest.postLogoutRedirectUri !== null) {\n if (logoutRequest && logoutRequest.postLogoutRedirectUri) {\n this.logger.verbose(\n \"Setting postLogoutRedirectUri to uri set on logout request\",\n validLogoutRequest.correlationId\n );\n validLogoutRequest.postLogoutRedirectUri =\n UrlString.getAbsoluteUrl(\n logoutRequest.postLogoutRedirectUri,\n BrowserUtils.getCurrentUri()\n );\n } else if (this.config.auth.postLogoutRedirectUri === null) {\n this.logger.verbose(\n \"postLogoutRedirectUri configured as null and no uri set on request, not passing post logout redirect\",\n validLogoutRequest.correlationId\n );\n } else if (this.config.auth.postLogoutRedirectUri) {\n this.logger.verbose(\n \"Setting postLogoutRedirectUri to configured uri\",\n validLogoutRequest.correlationId\n );\n validLogoutRequest.postLogoutRedirectUri =\n UrlString.getAbsoluteUrl(\n this.config.auth.postLogoutRedirectUri,\n BrowserUtils.getCurrentUri()\n );\n } else {\n this.logger.verbose(\n \"Setting postLogoutRedirectUri to current page\",\n validLogoutRequest.correlationId\n );\n validLogoutRequest.postLogoutRedirectUri =\n UrlString.getAbsoluteUrl(\n BrowserUtils.getCurrentUri(),\n BrowserUtils.getCurrentUri()\n );\n }\n } else {\n this.logger.verbose(\n \"postLogoutRedirectUri passed as null, not setting post logout redirect uri\",\n validLogoutRequest.correlationId\n );\n }\n\n return validLogoutRequest;\n }\n\n /**\n * Parses login_hint ID Token Claim out of AccountInfo object to be used as\n * logout_hint in end session request.\n * @param account\n */\n protected getLogoutHintFromIdTokenClaims(\n account: AccountInfo\n ): string | null {\n const idTokenClaims: IdTokenClaims | undefined = account.idTokenClaims;\n if (idTokenClaims) {\n if (idTokenClaims.login_hint) {\n return idTokenClaims.login_hint;\n } else {\n this.logger.verbose(\n \"The ID Token Claims tied to the provided account do not contain a login_hint claim, logoutHint will not be added to logout request\"\n );\n }\n } else {\n this.logger.verbose(\n \"The provided account does not contain ID Token Claims, logoutHint will not be added to logout request\"\n );\n }\n\n return null;\n }\n\n /**\n * Creates an Authorization Code Client with the given authority, or the default authority.\n * @param serverTelemetryManager\n * @param authorityUrl\n */\n protected async createAuthCodeClient(\n serverTelemetryManager: ServerTelemetryManager,\n authorityUrl?: string,\n requestAzureCloudOptions?: AzureCloudOptions,\n account?: AccountInfo\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.StandardInteractionClientCreateAuthCodeClient,\n this.correlationId\n );\n // Create auth module.\n const clientConfig = await invokeAsync(\n this.getClientConfiguration.bind(this),\n PerformanceEvents.StandardInteractionClientGetClientConfiguration,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(\n serverTelemetryManager,\n authorityUrl,\n requestAzureCloudOptions,\n account\n );\n return new AuthorizationCodeClient(\n clientConfig,\n this.performanceClient\n );\n }\n\n /**\n * Creates a Client Configuration object with the given request authority, or the default authority.\n * @param serverTelemetryManager\n * @param requestAuthority\n * @param requestCorrelationId\n */\n protected async getClientConfiguration(\n serverTelemetryManager: ServerTelemetryManager,\n requestAuthority?: string,\n requestAzureCloudOptions?: AzureCloudOptions,\n account?: AccountInfo\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.StandardInteractionClientGetClientConfiguration,\n this.correlationId\n );\n const discoveredAuthority = await invokeAsync(\n this.getDiscoveredAuthority.bind(this),\n PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(requestAuthority, requestAzureCloudOptions, account);\n const logger = this.config.system.loggerOptions;\n\n return {\n authOptions: {\n clientId: this.config.auth.clientId,\n authority: discoveredAuthority,\n clientCapabilities: this.config.auth.clientCapabilities,\n },\n systemOptions: {\n tokenRenewalOffsetSeconds:\n this.config.system.tokenRenewalOffsetSeconds,\n preventCorsPreflight: true,\n },\n loggerOptions: {\n loggerCallback: logger.loggerCallback,\n piiLoggingEnabled: logger.piiLoggingEnabled,\n logLevel: logger.logLevel,\n correlationId: this.correlationId,\n },\n cacheOptions: {\n claimsBasedCachingEnabled:\n this.config.cache.claimsBasedCachingEnabled,\n },\n cryptoInterface: this.browserCrypto,\n networkInterface: this.networkClient,\n storageInterface: this.browserStorage,\n serverTelemetryManager: serverTelemetryManager,\n libraryInfo: {\n sku: BrowserConstants.MSAL_SKU,\n version: version,\n cpu: Constants.EMPTY_STRING,\n os: Constants.EMPTY_STRING,\n },\n telemetry: this.config.telemetry,\n };\n }\n\n /**\n * Helper to initialize required request parameters for interactive APIs and ssoSilent()\n * @param request\n * @param interactionType\n */\n protected async initializeAuthorizationRequest(\n request: RedirectRequest | PopupRequest | SsoSilentRequest,\n interactionType: InteractionType\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest,\n this.correlationId\n );\n\n const redirectUri = this.getRedirectUri(request.redirectUri);\n const browserState: BrowserStateObject = {\n interactionType: interactionType,\n };\n const state = ProtocolUtils.setRequestState(\n this.browserCrypto,\n (request && request.state) || Constants.EMPTY_STRING,\n browserState\n );\n\n const baseRequest: BaseAuthRequest = await invokeAsync(\n this.initializeBaseRequest.bind(this),\n PerformanceEvents.InitializeBaseRequest,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(request);\n\n const validatedRequest: AuthorizationUrlRequest = {\n ...baseRequest,\n redirectUri: redirectUri,\n state: state,\n nonce: request.nonce || createNewGuid(),\n responseMode: this.config.auth.OIDCOptions\n .serverResponseType as ResponseMode,\n };\n\n const account =\n request.account || this.browserStorage.getActiveAccount();\n if (account) {\n this.logger.verbose(\n \"Setting validated request account\",\n this.correlationId\n );\n this.logger.verbosePii(\n `Setting validated request account: ${account.homeAccountId}`,\n this.correlationId\n );\n validatedRequest.account = account;\n }\n\n // Check for ADAL/MSAL v1 SSO\n if (!validatedRequest.loginHint && !account) {\n const legacyLoginHint = this.browserStorage.getLegacyLoginHint();\n if (legacyLoginHint) {\n validatedRequest.loginHint = legacyLoginHint;\n }\n }\n\n return validatedRequest;\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport const contentError = \"ContentError\";\nexport const userSwitch = \"user_switch\";\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n AuthError,\n InteractionRequiredAuthError,\n InteractionRequiredAuthErrorCodes,\n createInteractionRequiredAuthError,\n} from \"@azure/msal-common\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"./BrowserAuthError\";\n\nimport * as NativeAuthErrorCodes from \"./NativeAuthErrorCodes\";\nimport * as NativeStatusCodes from \"../broker/nativeBroker/NativeStatusCodes\";\nexport { NativeAuthErrorCodes };\n\nexport type OSError = {\n error?: number;\n protocol_error?: string;\n properties?: object;\n status?: string;\n retryable?: boolean;\n};\n\nconst INVALID_METHOD_ERROR = -2147186943;\n\nexport const NativeAuthErrorMessages = {\n [NativeAuthErrorCodes.userSwitch]:\n \"User attempted to switch accounts in the native broker, which is not allowed. All new accounts must sign-in through the standard web flow first, please try again.\",\n};\n\nexport class NativeAuthError extends AuthError {\n ext: OSError | undefined;\n\n constructor(errorCode: string, description?: string, ext?: OSError) {\n super(errorCode, description);\n\n Object.setPrototypeOf(this, NativeAuthError.prototype);\n this.name = \"NativeAuthError\";\n this.ext = ext;\n }\n}\n\n/**\n * These errors should result in a fallback to the 'standard' browser based auth flow.\n */\nexport function isFatalNativeAuthError(error: NativeAuthError): boolean {\n if (\n error.ext &&\n error.ext.status &&\n (error.ext.status === NativeStatusCodes.PERSISTENT_ERROR ||\n error.ext.status === NativeStatusCodes.DISABLED)\n ) {\n return true;\n }\n\n if (\n error.ext &&\n error.ext.error &&\n error.ext.error === INVALID_METHOD_ERROR\n ) {\n return true;\n }\n\n switch (error.errorCode) {\n case NativeAuthErrorCodes.contentError:\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Create the appropriate error object based on the WAM status code.\n * @param code\n * @param description\n * @param ext\n * @returns\n */\nexport function createNativeAuthError(\n code: string,\n description?: string,\n ext?: OSError\n): AuthError {\n if (ext && ext.status) {\n switch (ext.status) {\n case NativeStatusCodes.ACCOUNT_UNAVAILABLE:\n return createInteractionRequiredAuthError(\n InteractionRequiredAuthErrorCodes.nativeAccountUnavailable\n );\n case NativeStatusCodes.USER_INTERACTION_REQUIRED:\n return new InteractionRequiredAuthError(code, description);\n case NativeStatusCodes.USER_CANCEL:\n return createBrowserAuthError(\n BrowserAuthErrorCodes.userCancelled\n );\n case NativeStatusCodes.NO_NETWORK:\n return createBrowserAuthError(\n BrowserAuthErrorCodes.noNetworkConnectivity\n );\n }\n }\n\n return new NativeAuthError(\n code,\n NativeAuthErrorMessages[code] || description,\n ext\n );\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Status Codes that can be thrown by WAM\nexport const USER_INTERACTION_REQUIRED = \"USER_INTERACTION_REQUIRED\";\nexport const USER_CANCEL = \"USER_CANCEL\";\nexport const NO_NETWORK = \"NO_NETWORK\";\nexport const TRANSIENT_ERROR = \"TRANSIENT_ERROR\";\nexport const PERSISTENT_ERROR = \"PERSISTENT_ERROR\";\nexport const DISABLED = \"DISABLED\";\nexport const ACCOUNT_UNAVAILABLE = \"ACCOUNT_UNAVAILABLE\";\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n ClientConfiguration,\n isOidcProtocolMode,\n} from \"../config/ClientConfiguration\";\nimport { BaseClient } from \"./BaseClient\";\nimport { CommonRefreshTokenRequest } from \"../request/CommonRefreshTokenRequest\";\nimport { Authority } from \"../authority/Authority\";\nimport { ServerAuthorizationTokenResponse } from \"../response/ServerAuthorizationTokenResponse\";\nimport { RequestParameterBuilder } from \"../request/RequestParameterBuilder\";\nimport {\n GrantType,\n AuthenticationScheme,\n Errors,\n HeaderNames,\n} from \"../utils/Constants\";\nimport * as AADServerParamKeys from \"../constants/AADServerParamKeys\";\nimport { ResponseHandler } from \"../response/ResponseHandler\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport { PopTokenGenerator } from \"../crypto/PopTokenGenerator\";\nimport { StringUtils } from \"../utils/StringUtils\";\nimport { RequestThumbprint } from \"../network/RequestThumbprint\";\nimport { NetworkResponse } from \"../network/NetworkManager\";\nimport { CommonSilentFlowRequest } from \"../request/CommonSilentFlowRequest\";\nimport {\n createClientConfigurationError,\n ClientConfigurationErrorCodes,\n} from \"../error/ClientConfigurationError\";\nimport {\n createClientAuthError,\n ClientAuthErrorCodes,\n} from \"../error/ClientAuthError\";\nimport { ServerError } from \"../error/ServerError\";\nimport * as TimeUtils from \"../utils/TimeUtils\";\nimport { UrlString } from \"../url/UrlString\";\nimport { CcsCredentialType } from \"../account/CcsCredential\";\nimport { buildClientInfoFromHomeAccountId } from \"../account/ClientInfo\";\nimport {\n InteractionRequiredAuthError,\n InteractionRequiredAuthErrorCodes,\n createInteractionRequiredAuthError,\n} from \"../error/InteractionRequiredAuthError\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { invoke, invokeAsync } from \"../utils/FunctionWrappers\";\nimport { generateCredentialKey } from \"../cache/utils/CacheHelpers\";\n\nconst DEFAULT_REFRESH_TOKEN_EXPIRATION_OFFSET_SECONDS = 300; // 5 Minutes\n\n/**\n * OAuth2.0 refresh token client\n * @internal\n */\nexport class RefreshTokenClient extends BaseClient {\n constructor(\n configuration: ClientConfiguration,\n performanceClient?: IPerformanceClient\n ) {\n super(configuration, performanceClient);\n }\n public async acquireToken(\n request: CommonRefreshTokenRequest\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RefreshTokenClientAcquireToken,\n request.correlationId\n );\n\n const reqTimestamp = TimeUtils.nowSeconds();\n const response = await invokeAsync(\n this.executeTokenRequest.bind(this),\n PerformanceEvents.RefreshTokenClientExecuteTokenRequest,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, this.authority);\n\n // Retrieve requestId from response headers\n const requestId = response.headers?.[HeaderNames.X_MS_REQUEST_ID];\n const responseHandler = new ResponseHandler(\n this.config.authOptions.clientId,\n this.cacheManager,\n this.cryptoUtils,\n this.logger,\n this.config.serializableCache,\n this.config.persistencePlugin\n );\n responseHandler.validateTokenResponse(response.body);\n\n return invokeAsync(\n responseHandler.handleServerTokenResponse.bind(responseHandler),\n PerformanceEvents.HandleServerTokenResponse,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(\n response.body,\n this.authority,\n reqTimestamp,\n request,\n undefined,\n undefined,\n true,\n request.forceCache,\n requestId\n );\n }\n\n /**\n * Gets cached refresh token and attaches to request, then calls acquireToken API\n * @param request\n */\n public async acquireTokenByRefreshToken(\n request: CommonSilentFlowRequest\n ): Promise {\n // Cannot renew token if no request object is given.\n if (!request) {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.tokenRequestEmpty\n );\n }\n\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RefreshTokenClientAcquireTokenByRefreshToken,\n request.correlationId\n );\n\n // We currently do not support silent flow for account === null use cases; This will be revisited for confidential flow usecases\n if (!request.account) {\n throw createClientAuthError(\n ClientAuthErrorCodes.noAccountInSilentRequest\n );\n }\n\n // try checking if FOCI is enabled for the given application\n const isFOCI = this.cacheManager.isAppMetadataFOCI(\n request.account.environment\n );\n\n // if the app is part of the family, retrive a Family refresh token if present and make a refreshTokenRequest\n if (isFOCI) {\n try {\n return await invokeAsync(\n this.acquireTokenWithCachedRefreshToken.bind(this),\n PerformanceEvents.RefreshTokenClientAcquireTokenWithCachedRefreshToken,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, true);\n } catch (e) {\n const noFamilyRTInCache =\n e instanceof InteractionRequiredAuthError &&\n e.errorCode ===\n InteractionRequiredAuthErrorCodes.noTokensFound;\n const clientMismatchErrorWithFamilyRT =\n e instanceof ServerError &&\n e.errorCode === Errors.INVALID_GRANT_ERROR &&\n e.subError === Errors.CLIENT_MISMATCH_ERROR;\n\n // if family Refresh Token (FRT) cache acquisition fails or if client_mismatch error is seen with FRT, reattempt with application Refresh Token (ART)\n if (noFamilyRTInCache || clientMismatchErrorWithFamilyRT) {\n return invokeAsync(\n this.acquireTokenWithCachedRefreshToken.bind(this),\n PerformanceEvents.RefreshTokenClientAcquireTokenWithCachedRefreshToken,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, false);\n // throw in all other cases\n } else {\n throw e;\n }\n }\n }\n // fall back to application refresh token acquisition\n return invokeAsync(\n this.acquireTokenWithCachedRefreshToken.bind(this),\n PerformanceEvents.RefreshTokenClientAcquireTokenWithCachedRefreshToken,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, false);\n }\n\n /**\n * makes a network call to acquire tokens by exchanging RefreshToken available in userCache; throws if refresh token is not cached\n * @param request\n */\n private async acquireTokenWithCachedRefreshToken(\n request: CommonSilentFlowRequest,\n foci: boolean\n ) {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RefreshTokenClientAcquireTokenWithCachedRefreshToken,\n request.correlationId\n );\n\n // fetches family RT or application RT based on FOCI value\n const refreshToken = invoke(\n this.cacheManager.getRefreshToken.bind(this.cacheManager),\n PerformanceEvents.CacheManagerGetRefreshToken,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(\n request.account,\n foci,\n undefined,\n this.performanceClient,\n request.correlationId\n );\n\n if (!refreshToken) {\n throw createInteractionRequiredAuthError(\n InteractionRequiredAuthErrorCodes.noTokensFound\n );\n }\n\n if (\n refreshToken.expiresOn &&\n TimeUtils.isTokenExpired(\n refreshToken.expiresOn,\n request.refreshTokenExpirationOffsetSeconds ||\n DEFAULT_REFRESH_TOKEN_EXPIRATION_OFFSET_SECONDS\n )\n ) {\n throw createInteractionRequiredAuthError(\n InteractionRequiredAuthErrorCodes.refreshTokenExpired\n );\n }\n // attach cached RT size to the current measurement\n\n const refreshTokenRequest: CommonRefreshTokenRequest = {\n ...request,\n refreshToken: refreshToken.secret,\n authenticationScheme:\n request.authenticationScheme || AuthenticationScheme.BEARER,\n ccsCredential: {\n credential: request.account.homeAccountId,\n type: CcsCredentialType.HOME_ACCOUNT_ID,\n },\n };\n\n try {\n return await invokeAsync(\n this.acquireToken.bind(this),\n PerformanceEvents.RefreshTokenClientAcquireToken,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(refreshTokenRequest);\n } catch (e) {\n if (\n e instanceof InteractionRequiredAuthError &&\n e.subError === InteractionRequiredAuthErrorCodes.badToken\n ) {\n // Remove bad refresh token from cache\n this.logger.verbose(\n \"acquireTokenWithRefreshToken: bad refresh token, removing from cache\"\n );\n const badRefreshTokenKey = generateCredentialKey(refreshToken);\n this.cacheManager.removeRefreshToken(badRefreshTokenKey);\n }\n\n throw e;\n }\n }\n\n /**\n * Constructs the network message and makes a NW call to the underlying secure token service\n * @param request\n * @param authority\n */\n private async executeTokenRequest(\n request: CommonRefreshTokenRequest,\n authority: Authority\n ): Promise> {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RefreshTokenClientExecuteTokenRequest,\n request.correlationId\n );\n\n const queryParametersString = this.createTokenQueryParameters(request);\n const endpoint = UrlString.appendQueryString(\n authority.tokenEndpoint,\n queryParametersString\n );\n\n const requestBody = await invokeAsync(\n this.createTokenRequestBody.bind(this),\n PerformanceEvents.RefreshTokenClientCreateTokenRequestBody,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request);\n const headers: Record = this.createTokenRequestHeaders(\n request.ccsCredential\n );\n const thumbprint: RequestThumbprint = {\n clientId:\n request.tokenBodyParameters?.clientId ||\n this.config.authOptions.clientId,\n authority: authority.canonicalAuthority,\n scopes: request.scopes,\n claims: request.claims,\n authenticationScheme: request.authenticationScheme,\n resourceRequestMethod: request.resourceRequestMethod,\n resourceRequestUri: request.resourceRequestUri,\n shrClaims: request.shrClaims,\n sshKid: request.sshKid,\n };\n\n return invokeAsync(\n this.executePostToTokenEndpoint.bind(this),\n PerformanceEvents.RefreshTokenClientExecutePostToTokenEndpoint,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(\n endpoint,\n requestBody,\n headers,\n thumbprint,\n request.correlationId,\n PerformanceEvents.RefreshTokenClientExecutePostToTokenEndpoint\n );\n }\n\n /**\n * Helper function to create the token request body\n * @param request\n */\n private async createTokenRequestBody(\n request: CommonRefreshTokenRequest\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.RefreshTokenClientCreateTokenRequestBody,\n request.correlationId\n );\n\n const correlationId = request.correlationId;\n const parameterBuilder = new RequestParameterBuilder();\n\n parameterBuilder.addClientId(\n request.tokenBodyParameters?.[AADServerParamKeys.CLIENT_ID] ||\n this.config.authOptions.clientId\n );\n\n if (request.redirectUri) {\n parameterBuilder.addRedirectUri(request.redirectUri);\n }\n\n parameterBuilder.addScopes(\n request.scopes,\n true,\n this.config.authOptions.authority.options.OIDCOptions?.defaultScopes\n );\n\n parameterBuilder.addGrantType(GrantType.REFRESH_TOKEN_GRANT);\n\n parameterBuilder.addClientInfo();\n\n parameterBuilder.addLibraryInfo(this.config.libraryInfo);\n parameterBuilder.addApplicationTelemetry(\n this.config.telemetry.application\n );\n parameterBuilder.addThrottling();\n\n if (this.serverTelemetryManager && !isOidcProtocolMode(this.config)) {\n parameterBuilder.addServerTelemetry(this.serverTelemetryManager);\n }\n\n parameterBuilder.addCorrelationId(correlationId);\n\n parameterBuilder.addRefreshToken(request.refreshToken);\n\n if (this.config.clientCredentials.clientSecret) {\n parameterBuilder.addClientSecret(\n this.config.clientCredentials.clientSecret\n );\n }\n\n if (this.config.clientCredentials.clientAssertion) {\n const clientAssertion =\n this.config.clientCredentials.clientAssertion;\n parameterBuilder.addClientAssertion(clientAssertion.assertion);\n parameterBuilder.addClientAssertionType(\n clientAssertion.assertionType\n );\n }\n\n if (request.authenticationScheme === AuthenticationScheme.POP) {\n const popTokenGenerator = new PopTokenGenerator(\n this.cryptoUtils,\n this.performanceClient\n );\n const reqCnfData = await invokeAsync(\n popTokenGenerator.generateCnf.bind(popTokenGenerator),\n PerformanceEvents.PopTokenGenerateCnf,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(request, this.logger);\n // SPA PoP requires full Base64Url encoded req_cnf string (unhashed)\n parameterBuilder.addPopToken(reqCnfData.reqCnfString);\n } else if (request.authenticationScheme === AuthenticationScheme.SSH) {\n if (request.sshJwk) {\n parameterBuilder.addSshJwk(request.sshJwk);\n } else {\n throw createClientConfigurationError(\n ClientConfigurationErrorCodes.missingSshJwk\n );\n }\n }\n\n if (\n !StringUtils.isEmptyObj(request.claims) ||\n (this.config.authOptions.clientCapabilities &&\n this.config.authOptions.clientCapabilities.length > 0)\n ) {\n parameterBuilder.addClaims(\n request.claims,\n this.config.authOptions.clientCapabilities\n );\n }\n\n if (\n this.config.systemOptions.preventCorsPreflight &&\n request.ccsCredential\n ) {\n switch (request.ccsCredential.type) {\n case CcsCredentialType.HOME_ACCOUNT_ID:\n try {\n const clientInfo = buildClientInfoFromHomeAccountId(\n request.ccsCredential.credential\n );\n parameterBuilder.addCcsOid(clientInfo);\n } catch (e) {\n this.logger.verbose(\n \"Could not parse home account ID for CCS Header: \" +\n e\n );\n }\n break;\n case CcsCredentialType.UPN:\n parameterBuilder.addCcsUpn(\n request.ccsCredential.credential\n );\n break;\n }\n }\n\n if (request.tokenBodyParameters) {\n parameterBuilder.addExtraQueryParameters(\n request.tokenBodyParameters\n );\n }\n\n return parameterBuilder.createQueryString();\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { BaseClient } from \"./BaseClient\";\nimport { ClientConfiguration } from \"../config/ClientConfiguration\";\nimport { CommonSilentFlowRequest } from \"../request/CommonSilentFlowRequest\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport * as TimeUtils from \"../utils/TimeUtils\";\nimport { RefreshTokenClient } from \"./RefreshTokenClient\";\nimport {\n ClientAuthError,\n ClientAuthErrorCodes,\n createClientAuthError,\n} from \"../error/ClientAuthError\";\nimport { ResponseHandler } from \"../response/ResponseHandler\";\nimport { CacheRecord } from \"../cache/entities/CacheRecord\";\nimport { CacheOutcome } from \"../utils/Constants\";\nimport { IPerformanceClient } from \"../telemetry/performance/IPerformanceClient\";\nimport { StringUtils } from \"../utils/StringUtils\";\nimport { checkMaxAge, extractTokenClaims } from \"../account/AuthToken\";\nimport { TokenClaims } from \"../account/TokenClaims\";\nimport { PerformanceEvents } from \"../telemetry/performance/PerformanceEvent\";\nimport { invokeAsync } from \"../utils/FunctionWrappers\";\nimport { getTenantFromAuthorityString } from \"../authority/Authority\";\n\n/** @internal */\nexport class SilentFlowClient extends BaseClient {\n constructor(\n configuration: ClientConfiguration,\n performanceClient?: IPerformanceClient\n ) {\n super(configuration, performanceClient);\n }\n\n /**\n * Retrieves a token from cache if it is still valid, or uses the cached refresh token to renew\n * the given token and returns the renewed token\n * @param request\n */\n async acquireToken(\n request: CommonSilentFlowRequest\n ): Promise {\n try {\n const [authResponse, cacheOutcome] = await this.acquireCachedToken(\n request\n );\n\n // if the token is not expired but must be refreshed; get a new one in the background\n if (cacheOutcome === CacheOutcome.PROACTIVELY_REFRESHED) {\n this.logger.info(\n \"SilentFlowClient:acquireCachedToken - Cached access token's refreshOn property has been exceeded'. It's not expired, but must be refreshed.\"\n );\n\n // refresh the access token in the background\n const refreshTokenClient = new RefreshTokenClient(\n this.config,\n this.performanceClient\n );\n\n refreshTokenClient\n .acquireTokenByRefreshToken(request)\n .catch(() => {\n // do nothing, this is running in the background and no action is to be taken upon success or failure\n });\n }\n\n // return the cached token\n return authResponse;\n } catch (e) {\n if (\n e instanceof ClientAuthError &&\n e.errorCode === ClientAuthErrorCodes.tokenRefreshRequired\n ) {\n const refreshTokenClient = new RefreshTokenClient(\n this.config,\n this.performanceClient\n );\n return refreshTokenClient.acquireTokenByRefreshToken(request);\n } else {\n throw e;\n }\n }\n }\n\n /**\n * Retrieves token from cache or throws an error if it must be refreshed.\n * @param request\n */\n async acquireCachedToken(\n request: CommonSilentFlowRequest\n ): Promise<[AuthenticationResult, CacheOutcome]> {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.SilentFlowClientAcquireCachedToken,\n request.correlationId\n );\n let lastCacheOutcome: CacheOutcome = CacheOutcome.NOT_APPLICABLE;\n\n if (\n request.forceRefresh ||\n (!this.config.cacheOptions.claimsBasedCachingEnabled &&\n !StringUtils.isEmptyObj(request.claims))\n ) {\n // Must refresh due to present force_refresh flag.\n this.setCacheOutcome(\n CacheOutcome.FORCE_REFRESH_OR_CLAIMS,\n request.correlationId\n );\n throw createClientAuthError(\n ClientAuthErrorCodes.tokenRefreshRequired\n );\n }\n\n // We currently do not support silent flow for account === null use cases; This will be revisited for confidential flow usecases\n if (!request.account) {\n throw createClientAuthError(\n ClientAuthErrorCodes.noAccountInSilentRequest\n );\n }\n\n const requestTenantId =\n request.account.tenantId ||\n getTenantFromAuthorityString(request.authority);\n const tokenKeys = this.cacheManager.getTokenKeys();\n const cachedAccessToken = this.cacheManager.getAccessToken(\n request.account,\n request,\n tokenKeys,\n requestTenantId,\n this.performanceClient,\n request.correlationId\n );\n\n if (!cachedAccessToken) {\n // must refresh due to non-existent access_token\n this.setCacheOutcome(\n CacheOutcome.NO_CACHED_ACCESS_TOKEN,\n request.correlationId\n );\n throw createClientAuthError(\n ClientAuthErrorCodes.tokenRefreshRequired\n );\n } else if (\n TimeUtils.wasClockTurnedBack(cachedAccessToken.cachedAt) ||\n TimeUtils.isTokenExpired(\n cachedAccessToken.expiresOn,\n this.config.systemOptions.tokenRenewalOffsetSeconds\n )\n ) {\n // must refresh due to the expires_in value\n this.setCacheOutcome(\n CacheOutcome.CACHED_ACCESS_TOKEN_EXPIRED,\n request.correlationId\n );\n throw createClientAuthError(\n ClientAuthErrorCodes.tokenRefreshRequired\n );\n } else if (\n cachedAccessToken.refreshOn &&\n TimeUtils.isTokenExpired(cachedAccessToken.refreshOn, 0)\n ) {\n // must refresh (in the background) due to the refresh_in value\n lastCacheOutcome = CacheOutcome.PROACTIVELY_REFRESHED;\n\n // don't throw ClientAuthError.createRefreshRequiredError(), return cached token instead\n }\n\n const environment =\n request.authority || this.authority.getPreferredCache();\n const cacheRecord: CacheRecord = {\n account: this.cacheManager.readAccountFromCache(request.account),\n accessToken: cachedAccessToken,\n idToken: this.cacheManager.getIdToken(\n request.account,\n tokenKeys,\n requestTenantId,\n this.performanceClient,\n request.correlationId\n ),\n refreshToken: null,\n appMetadata:\n this.cacheManager.readAppMetadataFromCache(environment),\n };\n\n this.setCacheOutcome(lastCacheOutcome, request.correlationId);\n\n if (this.config.serverTelemetryManager) {\n this.config.serverTelemetryManager.incrementCacheHits();\n }\n\n return [\n await invokeAsync(\n this.generateResultFromCacheRecord.bind(this),\n PerformanceEvents.SilentFlowClientGenerateResultFromCacheRecord,\n this.logger,\n this.performanceClient,\n request.correlationId\n )(cacheRecord, request),\n lastCacheOutcome,\n ];\n }\n\n private setCacheOutcome(\n cacheOutcome: CacheOutcome,\n correlationId: string\n ): void {\n this.serverTelemetryManager?.setCacheOutcome(cacheOutcome);\n this.performanceClient?.addFields(\n {\n cacheOutcome: cacheOutcome,\n },\n correlationId\n );\n if (cacheOutcome !== CacheOutcome.NOT_APPLICABLE) {\n this.logger.info(\n `Token refresh is required due to cache outcome: ${cacheOutcome}`\n );\n }\n }\n\n /**\n * Helper function to build response object from the CacheRecord\n * @param cacheRecord\n */\n private async generateResultFromCacheRecord(\n cacheRecord: CacheRecord,\n request: CommonSilentFlowRequest\n ): Promise {\n this.performanceClient?.addQueueMeasurement(\n PerformanceEvents.SilentFlowClientGenerateResultFromCacheRecord,\n request.correlationId\n );\n let idTokenClaims: TokenClaims | undefined;\n if (cacheRecord.idToken) {\n idTokenClaims = extractTokenClaims(\n cacheRecord.idToken.secret,\n this.config.cryptoInterface.base64Decode\n );\n }\n\n // token max_age check\n if (request.maxAge || request.maxAge === 0) {\n const authTime = idTokenClaims?.auth_time;\n if (!authTime) {\n throw createClientAuthError(\n ClientAuthErrorCodes.authTimeNotFound\n );\n }\n\n checkMaxAge(authTime, request.maxAge);\n }\n\n return ResponseHandler.generateAuthenticationResult(\n this.cryptoUtils,\n this.authority,\n cacheRecord,\n true,\n request,\n idTokenClaims\n );\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { StandardInteractionClient } from \"./StandardInteractionClient\";\nimport {\n CommonSilentFlowRequest,\n SilentFlowClient,\n ServerTelemetryManager,\n AccountInfo,\n AzureCloudOptions,\n PerformanceEvents,\n invokeAsync,\n} from \"@azure/msal-common\";\nimport { SilentRequest } from \"../request/SilentRequest\";\nimport { ApiId } from \"../utils/BrowserConstants\";\nimport {\n BrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../error/BrowserAuthError\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport { ClearCacheRequest } from \"../request/ClearCacheRequest\";\n\nexport class SilentCacheClient extends StandardInteractionClient {\n /**\n * Returns unexpired tokens from the cache, if available\n * @param silentRequest\n */\n async acquireToken(\n silentRequest: CommonSilentFlowRequest\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.SilentCacheClientAcquireToken,\n silentRequest.correlationId\n );\n // Telemetry manager only used to increment cacheHits here\n const serverTelemetryManager = this.initializeServerTelemetryManager(\n ApiId.acquireTokenSilent_silentFlow\n );\n\n const silentAuthClient = await this.createSilentFlowClient(\n serverTelemetryManager,\n silentRequest.authority,\n silentRequest.azureCloudOptions,\n silentRequest.account\n );\n this.logger.verbose(\"Silent auth client created\");\n\n try {\n const response = await invokeAsync(\n silentAuthClient.acquireCachedToken.bind(silentAuthClient),\n PerformanceEvents.SilentFlowClientAcquireCachedToken,\n this.logger,\n this.performanceClient,\n silentRequest.correlationId\n )(silentRequest);\n const authResponse = response[0] as AuthenticationResult;\n\n this.performanceClient.addFields(\n {\n fromCache: true,\n },\n silentRequest.correlationId\n );\n return authResponse;\n } catch (error) {\n if (\n error instanceof BrowserAuthError &&\n error.errorCode === BrowserAuthErrorCodes.cryptoKeyNotFound\n ) {\n this.logger.verbose(\n \"Signing keypair for bound access token not found. Refreshing bound access token and generating a new crypto keypair.\"\n );\n }\n throw error;\n }\n }\n\n /**\n * API to silenty clear the browser cache.\n * @param logoutRequest\n */\n logout(logoutRequest?: ClearCacheRequest): Promise {\n this.logger.verbose(\"logoutRedirect called\");\n const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);\n return this.clearCacheOnLogout(validLogoutRequest?.account);\n }\n\n /**\n * Creates an Silent Flow Client with the given authority, or the default authority.\n * @param serverTelemetryManager\n * @param authorityUrl\n */\n protected async createSilentFlowClient(\n serverTelemetryManager: ServerTelemetryManager,\n authorityUrl?: string,\n azureCloudOptions?: AzureCloudOptions,\n account?: AccountInfo\n ): Promise {\n // Create auth module.\n const clientConfig = await invokeAsync(\n this.getClientConfiguration.bind(this),\n PerformanceEvents.StandardInteractionClientGetClientConfiguration,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(serverTelemetryManager, authorityUrl, azureCloudOptions, account);\n return new SilentFlowClient(clientConfig, this.performanceClient);\n }\n\n async initializeSilentRequest(\n request: SilentRequest,\n account: AccountInfo\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.InitializeSilentRequest,\n this.correlationId\n );\n\n const baseRequest = await invokeAsync(\n this.initializeBaseRequest.bind(this),\n PerformanceEvents.InitializeBaseRequest,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(request);\n return {\n ...request,\n ...baseRequest,\n account: account,\n forceRefresh: request.forceRefresh || false,\n };\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n Logger,\n ICrypto,\n PromptValue,\n AuthToken,\n Constants,\n AccountEntity,\n AuthorityType,\n ScopeSet,\n TimeUtils,\n AuthenticationScheme,\n UrlString,\n OIDC_DEFAULT_SCOPES,\n PopTokenGenerator,\n SignedHttpRequestParameters,\n IPerformanceClient,\n PerformanceEvents,\n IdTokenEntity,\n AccessTokenEntity,\n AuthError,\n CommonSilentFlowRequest,\n AccountInfo,\n CacheRecord,\n AADServerParamKeys,\n TokenClaims,\n createClientAuthError,\n ClientAuthErrorCodes,\n invokeAsync,\n createAuthError,\n AuthErrorCodes,\n updateAccountTenantProfileData,\n CacheHelpers,\n buildAccountToCache,\n} from \"@azure/msal-common\";\nimport { BaseInteractionClient } from \"./BaseInteractionClient\";\nimport { BrowserConfiguration } from \"../config/Configuration\";\nimport { BrowserCacheManager } from \"../cache/BrowserCacheManager\";\nimport { EventHandler } from \"../event/EventHandler\";\nimport { PopupRequest } from \"../request/PopupRequest\";\nimport { SilentRequest } from \"../request/SilentRequest\";\nimport { SsoSilentRequest } from \"../request/SsoSilentRequest\";\nimport { NativeMessageHandler } from \"../broker/nativeBroker/NativeMessageHandler\";\nimport {\n NativeExtensionMethod,\n ApiId,\n TemporaryCacheKeys,\n NativeConstants,\n} from \"../utils/BrowserConstants\";\nimport {\n NativeExtensionRequestBody,\n NativeTokenRequest,\n} from \"../broker/nativeBroker/NativeRequest\";\nimport { MATS, NativeResponse } from \"../broker/nativeBroker/NativeResponse\";\nimport {\n NativeAuthError,\n NativeAuthErrorCodes,\n createNativeAuthError,\n isFatalNativeAuthError,\n} from \"../error/NativeAuthError\";\nimport { RedirectRequest } from \"../request/RedirectRequest\";\nimport { NavigationOptions } from \"../navigation/NavigationOptions\";\nimport { INavigationClient } from \"../navigation/INavigationClient\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../error/BrowserAuthError\";\nimport { SilentCacheClient } from \"./SilentCacheClient\";\nimport { AuthenticationResult } from \"../response/AuthenticationResult\";\nimport { base64Decode } from \"../encode/Base64Decode\";\n\nconst BrokerServerParamKeys = {\n BROKER_CLIENT_ID: \"brk_client_id\",\n BROKER_REDIRECT_URI: \"brk_redirect_uri\",\n};\n\nexport class NativeInteractionClient extends BaseInteractionClient {\n protected apiId: ApiId;\n protected accountId: string;\n protected nativeMessageHandler: NativeMessageHandler;\n protected silentCacheClient: SilentCacheClient;\n protected nativeStorageManager: BrowserCacheManager;\n\n constructor(\n config: BrowserConfiguration,\n browserStorage: BrowserCacheManager,\n browserCrypto: ICrypto,\n logger: Logger,\n eventHandler: EventHandler,\n navigationClient: INavigationClient,\n apiId: ApiId,\n performanceClient: IPerformanceClient,\n provider: NativeMessageHandler,\n accountId: string,\n nativeStorageImpl: BrowserCacheManager,\n correlationId?: string\n ) {\n super(\n config,\n browserStorage,\n browserCrypto,\n logger,\n eventHandler,\n navigationClient,\n performanceClient,\n provider,\n correlationId\n );\n this.apiId = apiId;\n this.accountId = accountId;\n this.nativeMessageHandler = provider;\n this.nativeStorageManager = nativeStorageImpl;\n this.silentCacheClient = new SilentCacheClient(\n config,\n this.nativeStorageManager,\n browserCrypto,\n logger,\n eventHandler,\n navigationClient,\n performanceClient,\n provider,\n correlationId\n );\n }\n\n /**\n * Acquire token from native platform via browser extension\n * @param request\n */\n async acquireToken(\n request: PopupRequest | SilentRequest | SsoSilentRequest\n ): Promise {\n this.performanceClient.addQueueMeasurement(\n PerformanceEvents.NativeInteractionClientAcquireToken,\n request.correlationId\n );\n this.logger.trace(\"NativeInteractionClient - acquireToken called.\");\n\n // start the perf measurement\n const nativeATMeasurement = this.performanceClient.startMeasurement(\n PerformanceEvents.NativeInteractionClientAcquireToken,\n request.correlationId\n );\n const reqTimestamp = TimeUtils.nowSeconds();\n\n // initialize native request\n const nativeRequest = await this.initializeNativeRequest(request);\n\n // check if the tokens can be retrieved from internal cache\n try {\n const result = await this.acquireTokensFromCache(\n this.accountId,\n nativeRequest\n );\n nativeATMeasurement.end({\n success: true,\n isNativeBroker: false, // Should be true only when the result is coming directly from the broker\n fromCache: true,\n });\n return result;\n } catch (e) {\n // continue with a native call for any and all errors\n this.logger.info(\n \"MSAL internal Cache does not contain tokens, proceed to make a native call\"\n );\n }\n\n // fall back to native calls\n const messageBody: NativeExtensionRequestBody = {\n method: NativeExtensionMethod.GetToken,\n request: nativeRequest,\n };\n\n const response: object = await this.nativeMessageHandler.sendMessage(\n messageBody\n );\n const validatedResponse: NativeResponse =\n this.validateNativeResponse(response);\n\n return this.handleNativeResponse(\n validatedResponse,\n nativeRequest,\n reqTimestamp\n )\n .then((result: AuthenticationResult) => {\n nativeATMeasurement.end({\n success: true,\n isNativeBroker: true,\n requestId: result.requestId,\n });\n return result;\n })\n .catch((error: AuthError) => {\n nativeATMeasurement.end({\n success: false,\n errorCode: error.errorCode,\n subErrorCode: error.subError,\n isNativeBroker: true,\n });\n throw error;\n });\n }\n\n /**\n * Creates silent flow request\n * @param request\n * @param cachedAccount\n * @returns CommonSilentFlowRequest\n */\n private createSilentCacheRequest(\n request: NativeTokenRequest,\n cachedAccount: AccountInfo\n ): CommonSilentFlowRequest {\n return {\n authority: request.authority,\n correlationId: this.correlationId,\n scopes: ScopeSet.fromString(request.scope).asArray(),\n account: cachedAccount,\n forceRefresh: false,\n };\n }\n\n /**\n * Fetches the tokens from the cache if un-expired\n * @param nativeAccountId\n * @param request\n * @returns authenticationResult\n */\n protected async acquireTokensFromCache(\n nativeAccountId: string,\n request: NativeTokenRequest\n ): Promise {\n if (!nativeAccountId) {\n this.logger.warning(\n \"NativeInteractionClient:acquireTokensFromCache - No nativeAccountId provided\"\n );\n throw createClientAuthError(ClientAuthErrorCodes.noAccountFound);\n }\n // fetch the account from browser cache\n const account = this.browserStorage.getBaseAccountInfo({\n nativeAccountId,\n });\n\n if (!account) {\n throw createClientAuthError(ClientAuthErrorCodes.noAccountFound);\n }\n\n // leverage silent flow for cached tokens retrieval\n try {\n const silentRequest = this.createSilentCacheRequest(\n request,\n account\n );\n const result = await this.silentCacheClient.acquireToken(\n silentRequest\n );\n\n const fullAccount = {\n ...account,\n idTokenClaims: result?.idTokenClaims as TokenClaims,\n idToken: result?.idToken,\n };\n\n return {\n ...result,\n account: fullAccount,\n };\n } catch (e) {\n throw e;\n }\n }\n\n /**\n * Acquires a token from native platform then redirects to the redirectUri instead of returning the response\n * @param request\n */\n async acquireTokenRedirect(request: RedirectRequest): Promise {\n this.logger.trace(\n \"NativeInteractionClient - acquireTokenRedirect called.\"\n );\n const nativeRequest = await this.initializeNativeRequest(request);\n\n const messageBody: NativeExtensionRequestBody = {\n method: NativeExtensionMethod.GetToken,\n request: nativeRequest,\n };\n\n try {\n const response: object =\n await this.nativeMessageHandler.sendMessage(messageBody);\n this.validateNativeResponse(response);\n } catch (e) {\n // Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise\n if (e instanceof NativeAuthError && isFatalNativeAuthError(e)) {\n throw e;\n }\n }\n this.browserStorage.setTemporaryCache(\n TemporaryCacheKeys.NATIVE_REQUEST,\n JSON.stringify(nativeRequest),\n true\n );\n\n const navigationOptions: NavigationOptions = {\n apiId: ApiId.acquireTokenRedirect,\n timeout: this.config.system.redirectNavigationTimeout,\n noHistory: false,\n };\n const redirectUri = this.config.auth.navigateToLoginRequestUrl\n ? window.location.href\n : this.getRedirectUri(request.redirectUri);\n await this.navigationClient.navigateExternal(\n redirectUri,\n navigationOptions\n ); // Need to treat this as external to ensure handleRedirectPromise is run again\n }\n\n /**\n * If the previous page called native platform for a token using redirect APIs, send the same request again and return the response\n * @param performanceClient {IPerformanceClient?}\n * @param correlationId {string?} correlation identifier\n */\n async handleRedirectPromise(\n performanceClient?: IPerformanceClient,\n correlationId?: string\n ): Promise {\n this.logger.trace(\n \"NativeInteractionClient - handleRedirectPromise called.\"\n );\n if (!this.browserStorage.isInteractionInProgress(true)) {\n this.logger.info(\n \"handleRedirectPromise called but there is no interaction in progress, returning null.\"\n );\n return null;\n }\n\n // remove prompt from the request to prevent WAM from prompting twice\n const cachedRequest = this.browserStorage.getCachedNativeRequest();\n if (!cachedRequest) {\n this.logger.verbose(\n \"NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.\"\n );\n if (performanceClient && correlationId) {\n performanceClient?.addFields(\n { errorCode: \"no_cached_request\" },\n correlationId\n );\n }\n return null;\n }\n\n const { prompt, ...request } = cachedRequest;\n if (prompt) {\n this.logger.verbose(\n \"NativeInteractionClient - handleRedirectPromise called and prompt was included in the original request, removing prompt from cached request to prevent second interaction with native broker window.\"\n );\n }\n\n this.browserStorage.removeItem(\n this.browserStorage.generateCacheKey(\n TemporaryCacheKeys.NATIVE_REQUEST\n )\n );\n\n const messageBody: NativeExtensionRequestBody = {\n method: NativeExtensionMethod.GetToken,\n request: request,\n };\n\n const reqTimestamp = TimeUtils.nowSeconds();\n\n try {\n this.logger.verbose(\n \"NativeInteractionClient - handleRedirectPromise sending message to native broker.\"\n );\n const response: object =\n await this.nativeMessageHandler.sendMessage(messageBody);\n this.validateNativeResponse(response);\n const result = this.handleNativeResponse(\n response as NativeResponse,\n request,\n reqTimestamp\n );\n this.browserStorage.setInteractionInProgress(false);\n return await result;\n } catch (e) {\n this.browserStorage.setInteractionInProgress(false);\n throw e;\n }\n }\n\n /**\n * Logout from native platform via browser extension\n * @param request\n */\n logout(): Promise {\n this.logger.trace(\"NativeInteractionClient - logout called.\");\n return Promise.reject(\"Logout not implemented yet\");\n }\n\n /**\n * Transform response from native platform into AuthenticationResult object which will be returned to the end user\n * @param response\n * @param request\n * @param reqTimestamp\n */\n protected async handleNativeResponse(\n response: NativeResponse,\n request: NativeTokenRequest,\n reqTimestamp: number\n ): Promise {\n this.logger.trace(\n \"NativeInteractionClient - handleNativeResponse called.\"\n );\n\n // generate identifiers\n const idTokenClaims = AuthToken.extractTokenClaims(\n response.id_token,\n base64Decode\n );\n\n const homeAccountIdentifier = this.createHomeAccountIdentifier(\n response,\n idTokenClaims\n );\n\n const cachedhomeAccountId =\n this.browserStorage.getAccountInfoFilteredBy({\n nativeAccountId: request.accountId,\n })?.homeAccountId;\n\n if (\n homeAccountIdentifier !== cachedhomeAccountId &&\n response.account.id !== request.accountId\n ) {\n // User switch in native broker prompt is not supported. All users must first sign in through web flow to ensure server state is in sync\n throw createNativeAuthError(NativeAuthErrorCodes.userSwitch);\n }\n\n // Get the preferred_cache domain for the given authority\n const authority = await this.getDiscoveredAuthority(request.authority);\n\n const baseAccount = buildAccountToCache(\n this.browserStorage,\n authority,\n homeAccountIdentifier,\n idTokenClaims,\n base64Decode,\n response.client_info,\n undefined, // environment\n idTokenClaims.tid,\n undefined, // auth code payload\n response.account.id,\n this.logger\n );\n\n // generate authenticationResult\n const result = await this.generateAuthenticationResult(\n response,\n request,\n idTokenClaims,\n baseAccount,\n authority.canonicalAuthority,\n reqTimestamp\n );\n\n // cache accounts and tokens in the appropriate storage\n this.cacheAccount(baseAccount);\n this.cacheNativeTokens(\n response,\n request,\n homeAccountIdentifier,\n idTokenClaims,\n result.accessToken,\n result.tenantId,\n reqTimestamp\n );\n\n return result;\n }\n\n /**\n * creates an homeAccountIdentifier for the account\n * @param response\n * @param idTokenObj\n * @returns\n */\n protected createHomeAccountIdentifier(\n response: NativeResponse,\n idTokenClaims: TokenClaims\n ): string {\n // Save account in browser storage\n const homeAccountIdentifier = AccountEntity.generateHomeAccountId(\n response.client_info || Constants.EMPTY_STRING,\n AuthorityType.Default,\n this.logger,\n this.browserCrypto,\n idTokenClaims\n );\n\n return homeAccountIdentifier;\n }\n\n /**\n * Helper to generate scopes\n * @param response\n * @param request\n * @returns\n */\n generateScopes(\n response: NativeResponse,\n request: NativeTokenRequest\n ): ScopeSet {\n return response.scope\n ? ScopeSet.fromString(response.scope)\n : ScopeSet.fromString(request.scope);\n }\n\n /**\n * If PoP token is requesred, records the PoP token if returned from the WAM, else generates one in the browser\n * @param request\n * @param response\n */\n async generatePopAccessToken(\n response: NativeResponse,\n request: NativeTokenRequest\n ): Promise {\n if (request.tokenType === AuthenticationScheme.POP) {\n /**\n * This code prioritizes SHR returned from the native layer. In case of error/SHR not calculated from WAM and the AT\n * is still received, SHR is calculated locally\n */\n\n // Check if native layer returned an SHR token\n if (response.shr) {\n this.logger.trace(\n \"handleNativeServerResponse: SHR is enabled in native layer\"\n );\n return response.shr;\n }\n\n // Generate SHR in msal js if WAM does not compute it when POP is enabled\n const popTokenGenerator: PopTokenGenerator = new PopTokenGenerator(\n this.browserCrypto\n );\n const shrParameters: SignedHttpRequestParameters = {\n resourceRequestMethod: request.resourceRequestMethod,\n resourceRequestUri: request.resourceRequestUri,\n shrClaims: request.shrClaims,\n shrNonce: request.shrNonce,\n };\n\n /**\n * KeyID must be present in the native request from when the PoP key was generated in order for\n * PopTokenGenerator to query the full key for signing\n */\n if (!request.keyId) {\n throw createClientAuthError(ClientAuthErrorCodes.keyIdMissing);\n }\n return popTokenGenerator.signPopToken(\n response.access_token,\n request.keyId,\n shrParameters\n );\n } else {\n return response.access_token;\n }\n }\n\n /**\n * Generates authentication result\n * @param response\n * @param request\n * @param idTokenObj\n * @param accountEntity\n * @param authority\n * @param reqTimestamp\n * @returns\n */\n protected async generateAuthenticationResult(\n response: NativeResponse,\n request: NativeTokenRequest,\n idTokenClaims: TokenClaims,\n accountEntity: AccountEntity,\n authority: string,\n reqTimestamp: number\n ): Promise {\n // Add Native Broker fields to Telemetry\n const mats = this.addTelemetryFromNativeResponse(response);\n\n // If scopes not returned in server response, use request scopes\n const responseScopes = response.scope\n ? ScopeSet.fromString(response.scope)\n : ScopeSet.fromString(request.scope);\n\n const accountProperties = response.account.properties || {};\n const uid =\n accountProperties[\"UID\"] ||\n idTokenClaims.oid ||\n idTokenClaims.sub ||\n Constants.EMPTY_STRING;\n const tid =\n accountProperties[\"TenantId\"] ||\n idTokenClaims.tid ||\n Constants.EMPTY_STRING;\n\n const accountInfo: AccountInfo | null = updateAccountTenantProfileData(\n accountEntity.getAccountInfo(),\n undefined, // tenantProfile optional\n idTokenClaims,\n response.id_token\n );\n\n /**\n * In pairwise broker flows, this check prevents the broker's native account id\n * from being returned over the embedded app's account id.\n */\n if (accountInfo.nativeAccountId !== response.account.id) {\n accountInfo.nativeAccountId = response.account.id;\n }\n\n // generate PoP token as needed\n const responseAccessToken = await this.generatePopAccessToken(\n response,\n request\n );\n const tokenType =\n request.tokenType === AuthenticationScheme.POP\n ? AuthenticationScheme.POP\n : AuthenticationScheme.BEARER;\n\n const result: AuthenticationResult = {\n authority: authority,\n uniqueId: uid,\n tenantId: tid,\n scopes: responseScopes.asArray(),\n account: accountInfo,\n idToken: response.id_token,\n idTokenClaims: idTokenClaims,\n accessToken: responseAccessToken,\n fromCache: mats ? this.isResponseFromCache(mats) : false,\n expiresOn: new Date(\n Number(reqTimestamp + response.expires_in) * 1000\n ),\n tokenType: tokenType,\n correlationId: this.correlationId,\n state: response.state,\n fromNativeBroker: true,\n };\n\n return result;\n }\n\n /**\n * cache the account entity in browser storage\n * @param accountEntity\n */\n cacheAccount(accountEntity: AccountEntity): void {\n // Store the account info and hence `nativeAccountId` in browser cache\n this.browserStorage.setAccount(accountEntity);\n\n // Remove any existing cached tokens for this account in browser storage\n this.browserStorage.removeAccountContext(accountEntity).catch((e) => {\n this.logger.error(\n `Error occurred while removing account context from browser storage. ${e}`\n );\n });\n }\n\n /**\n * Stores the access_token and id_token in inmemory storage\n * @param response\n * @param request\n * @param homeAccountIdentifier\n * @param idTokenObj\n * @param responseAccessToken\n * @param tenantId\n * @param reqTimestamp\n */\n cacheNativeTokens(\n response: NativeResponse,\n request: NativeTokenRequest,\n homeAccountIdentifier: string,\n idTokenClaims: TokenClaims,\n responseAccessToken: string,\n tenantId: string,\n reqTimestamp: number\n ): void {\n const cachedIdToken: IdTokenEntity | null =\n CacheHelpers.createIdTokenEntity(\n homeAccountIdentifier,\n request.authority,\n response.id_token || \"\",\n request.clientId,\n idTokenClaims.tid || \"\"\n );\n\n // cache accessToken in inmemory storage\n const expiresIn: number =\n request.tokenType === AuthenticationScheme.POP\n ? Constants.SHR_NONCE_VALIDITY\n : (typeof response.expires_in === \"string\"\n ? parseInt(response.expires_in, 10)\n : response.expires_in) || 0;\n const tokenExpirationSeconds = reqTimestamp + expiresIn;\n const responseScopes = this.generateScopes(response, request);\n\n const cachedAccessToken: AccessTokenEntity | null =\n CacheHelpers.createAccessTokenEntity(\n homeAccountIdentifier,\n request.authority,\n responseAccessToken,\n request.clientId,\n idTokenClaims.tid || tenantId,\n responseScopes.printScopes(),\n tokenExpirationSeconds,\n 0,\n base64Decode\n );\n\n const nativeCacheRecord = new CacheRecord(\n undefined,\n cachedIdToken,\n cachedAccessToken\n );\n\n void this.nativeStorageManager.saveCacheRecord(\n nativeCacheRecord,\n request.storeInCache\n );\n }\n\n protected addTelemetryFromNativeResponse(\n response: NativeResponse\n ): MATS | null {\n const mats = this.getMATSFromResponse(response);\n\n if (!mats) {\n return null;\n }\n\n this.performanceClient.addFields(\n {\n extensionId: this.nativeMessageHandler.getExtensionId(),\n extensionVersion:\n this.nativeMessageHandler.getExtensionVersion(),\n matsBrokerVersion: mats.broker_version,\n matsAccountJoinOnStart: mats.account_join_on_start,\n matsAccountJoinOnEnd: mats.account_join_on_end,\n matsDeviceJoin: mats.device_join,\n matsPromptBehavior: mats.prompt_behavior,\n matsApiErrorCode: mats.api_error_code,\n matsUiVisible: mats.ui_visible,\n matsSilentCode: mats.silent_code,\n matsSilentBiSubCode: mats.silent_bi_sub_code,\n matsSilentMessage: mats.silent_message,\n matsSilentStatus: mats.silent_status,\n matsHttpStatus: mats.http_status,\n matsHttpEventCount: mats.http_event_count,\n },\n this.correlationId\n );\n\n return mats;\n }\n\n /**\n * Validates native platform response before processing\n * @param response\n */\n private validateNativeResponse(response: object): NativeResponse {\n if (\n response.hasOwnProperty(\"access_token\") &&\n response.hasOwnProperty(\"id_token\") &&\n response.hasOwnProperty(\"client_info\") &&\n response.hasOwnProperty(\"account\") &&\n response.hasOwnProperty(\"scope\") &&\n response.hasOwnProperty(\"expires_in\")\n ) {\n return response as NativeResponse;\n } else {\n throw createAuthError(\n AuthErrorCodes.unexpectedError,\n \"Response missing expected properties.\"\n );\n }\n }\n\n /**\n * Gets MATS telemetry from native response\n * @param response\n * @returns\n */\n private getMATSFromResponse(response: NativeResponse): MATS | null {\n if (response.properties.MATS) {\n try {\n return JSON.parse(response.properties.MATS);\n } catch (e) {\n this.logger.error(\n \"NativeInteractionClient - Error parsing MATS telemetry, returning null instead\"\n );\n }\n }\n\n return null;\n }\n\n /**\n * Returns whether or not response came from native cache\n * @param response\n * @returns\n */\n protected isResponseFromCache(mats: MATS): boolean {\n if (typeof mats.is_cached === \"undefined\") {\n this.logger.verbose(\n \"NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.\"\n );\n return false;\n }\n\n return !!mats.is_cached;\n }\n\n /**\n * Translates developer provided request object into NativeRequest object\n * @param request\n */\n protected async initializeNativeRequest(\n request: PopupRequest | SsoSilentRequest\n ): Promise {\n this.logger.trace(\n \"NativeInteractionClient - initializeNativeRequest called\"\n );\n\n const authority = request.authority || this.config.auth.authority;\n\n if (request.account) {\n // validate authority\n await this.getDiscoveredAuthority(\n authority,\n request.azureCloudOptions,\n request.account\n );\n }\n\n const canonicalAuthority = new UrlString(authority);\n canonicalAuthority.validateAsUri();\n\n // scopes are expected to be received by the native broker as \"scope\" and will be added to the request below. Other properties that should be dropped from the request to the native broker can be included in the object destructuring here.\n const { scopes, ...remainingProperties } = request;\n const scopeSet = new ScopeSet(scopes || []);\n scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);\n\n const getPrompt = () => {\n // If request is silent, prompt is always none\n switch (this.apiId) {\n case ApiId.ssoSilent:\n case ApiId.acquireTokenSilent_silentFlow:\n this.logger.trace(\n \"initializeNativeRequest: silent request sets prompt to none\"\n );\n return PromptValue.NONE;\n default:\n break;\n }\n\n // Prompt not provided, request may proceed and native broker decides if it needs to prompt\n if (!request.prompt) {\n this.logger.trace(\n \"initializeNativeRequest: prompt was not provided\"\n );\n return undefined;\n }\n\n // If request is interactive, check if prompt provided is allowed to go directly to native broker\n switch (request.prompt) {\n case PromptValue.NONE:\n case PromptValue.CONSENT:\n case PromptValue.LOGIN:\n this.logger.trace(\n \"initializeNativeRequest: prompt is compatible with native flow\"\n );\n return request.prompt;\n default:\n this.logger.trace(\n `initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`\n );\n throw createBrowserAuthError(\n BrowserAuthErrorCodes.nativePromptNotSupported\n );\n }\n };\n\n const validatedRequest: NativeTokenRequest = {\n ...remainingProperties,\n accountId: this.accountId,\n clientId: this.config.auth.clientId,\n authority: canonicalAuthority.urlString,\n scope: scopeSet.printScopes(),\n redirectUri: this.getRedirectUri(request.redirectUri),\n prompt: getPrompt(),\n correlationId: this.correlationId,\n tokenType: request.authenticationScheme,\n windowTitleSubstring: document.title,\n extraParameters: {\n ...request.extraQueryParameters,\n ...request.tokenQueryParameters,\n },\n extendedExpiryToken: false, // Make this configurable?\n };\n\n this.handleExtraBrokerParams(validatedRequest);\n validatedRequest.extraParameters =\n validatedRequest.extraParameters || {};\n validatedRequest.extraParameters.telemetry =\n NativeConstants.MATS_TELEMETRY;\n\n if (request.authenticationScheme === AuthenticationScheme.POP) {\n // add POP request type\n const shrParameters: SignedHttpRequestParameters = {\n resourceRequestUri: request.resourceRequestUri,\n resourceRequestMethod: request.resourceRequestMethod,\n shrClaims: request.shrClaims,\n shrNonce: request.shrNonce,\n };\n\n const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);\n const reqCnfData = await invokeAsync(\n popTokenGenerator.generateCnf.bind(popTokenGenerator),\n PerformanceEvents.PopTokenGenerateCnf,\n this.logger,\n this.performanceClient,\n this.correlationId\n )(shrParameters, this.logger);\n\n // to reduce the URL length, it is recommended to send the hash of the req_cnf instead of the whole string\n validatedRequest.reqCnf = reqCnfData.reqCnfHash;\n validatedRequest.keyId = reqCnfData.kid;\n }\n\n return validatedRequest;\n }\n\n /**\n * Handles extra broker request parameters\n * @param request {NativeTokenRequest}\n * @private\n */\n private handleExtraBrokerParams(request: NativeTokenRequest): void {\n if (!request.extraParameters) {\n return;\n }\n\n if (\n request.extraParameters.hasOwnProperty(\n BrokerServerParamKeys.BROKER_CLIENT_ID\n ) &&\n request.extraParameters.hasOwnProperty(\n BrokerServerParamKeys.BROKER_REDIRECT_URI\n ) &&\n request.extraParameters.hasOwnProperty(AADServerParamKeys.CLIENT_ID)\n ) {\n const child_client_id =\n request.extraParameters[AADServerParamKeys.CLIENT_ID];\n const child_redirect_uri = request.redirectUri;\n const brk_redirect_uri =\n request.extraParameters[\n BrokerServerParamKeys.BROKER_REDIRECT_URI\n ];\n request.extraParameters = {\n child_client_id,\n child_redirect_uri,\n };\n request.redirectUri = brk_redirect_uri;\n }\n }\n}\n","/*\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n NativeConstants,\n NativeExtensionMethod,\n} from \"../../utils/BrowserConstants\";\nimport {\n Logger,\n AuthError,\n createAuthError,\n AuthErrorCodes,\n AuthenticationScheme,\n InProgressPerformanceEvent,\n PerformanceEvents,\n IPerformanceClient,\n} from \"@azure/msal-common\";\nimport {\n NativeExtensionRequest,\n NativeExtensionRequestBody,\n} from \"./NativeRequest\";\nimport { createNativeAuthError } from \"../../error/NativeAuthError\";\nimport {\n createBrowserAuthError,\n BrowserAuthErrorCodes,\n} from \"../../error/BrowserAuthError\";\nimport { BrowserConfiguration } from \"../../config/Configuration\";\nimport { createNewGuid } from \"../../crypto/BrowserCrypto\";\n\ntype ResponseResolvers = {\n resolve: (value: T | PromiseLike) => void;\n reject: (\n value: AuthError | Error | PromiseLike | PromiseLike\n ) => void;\n};\n\nexport class NativeMessageHandler {\n private extensionId: string | undefined;\n private extensionVersion: string | undefined;\n private logger: Logger;\n private readonly handshakeTimeoutMs: number;\n private timeoutId: number | undefined;\n private resolvers: Map>;\n private handshakeResolvers: Map>;\n private messageChannel: MessageChannel;\n private readonly windowListener: (event: MessageEvent) => void;\n private readonly performanceClient: IPerformanceClient;\n private readonly handshakeEvent: InProgressPerformanceEvent;\n\n constructor(\n logger: Logger,\n handshakeTimeoutMs: number,\n performanceClient: IPerformanceClient,\n extensionId?: string\n ) {\n this.logger = logger;\n this.handshakeTimeoutMs = handshakeTimeoutMs;\n this.extensionId = extensionId;\n this.resolvers = new Map(); // Used for non-handshake messages\n this.handshakeResolvers = new Map(); // Used for handshake messages\n this.messageChannel = new MessageChannel();\n this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound\n this.performanceClient = performanceClient;\n this.handshakeEvent = performanceClient.startMeasurement(\n PerformanceEvents.NativeMessageHandlerHandshake\n );\n }\n\n /**\n * Sends a given message to the extension and resolves with the extension response\n * @param body\n */\n async sendMessage(body: NativeExtensionRequestBody): Promise