/*! @azure/msal-browser v2.30.0 2022-10-10 */
'use strict';
import { __extends, __spread, __awaiter, __generator } from '../_virtual/_tslib.js';
import { AccountEntity, CacheManager, IdTokenEntity, AccessTokenEntity, RefreshTokenEntity, AppMetadataEntity, ServerTelemetryEntity, AuthorityMetadataEntity, Constants, PersistentCacheKeys, ClientAuthError, ThrottlingEntity, StringUtils, ProtocolUtils, CcsCredentialType, IdToken, DEFAULT_CRYPTO_IMPLEMENTATION } from '@azure/msal-common';
import { BrowserAuthError } from '../error/BrowserAuthError.js';
import { BrowserCacheLocation, InMemoryCacheKeys, TemporaryCacheKeys } from '../utils/BrowserConstants.js';
import { BrowserStorage } from './BrowserStorage.js';
import { MemoryStorage } from './MemoryStorage.js';
import { BrowserProtocolUtils } from '../utils/BrowserProtocolUtils.js';

/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
/**
 * This class implements the cache storage interface for MSAL through browser local or session storage.
 * Cookies are only used if storeAuthStateInCookie is true, and are only used for
 * parameters such as state and nonce, generally.
 */
var BrowserCacheManager = /** @class */ (function (_super) {
    __extends(BrowserCacheManager, _super);
    function BrowserCacheManager(clientId, cacheConfig, cryptoImpl, logger) {
        var _this = _super.call(this, clientId, cryptoImpl) || this;
        // Cookie life calculation (hours * minutes * seconds * ms)
        _this.COOKIE_LIFE_MULTIPLIER = 24 * 60 * 60 * 1000;
        _this.cacheConfig = cacheConfig;
        _this.logger = logger;
        _this.internalStorage = new MemoryStorage();
        _this.browserStorage = _this.setupBrowserStorage(_this.cacheConfig.cacheLocation);
        _this.temporaryCacheStorage = _this.setupTemporaryCacheStorage(_this.cacheConfig.cacheLocation);
        // Migrate any cache entries from older versions of MSAL.
        _this.migrateCacheEntries();
        return _this;
    }
    /**
     * Returns a window storage class implementing the IWindowStorage interface that corresponds to the configured cacheLocation.
     * @param cacheLocation
     */
    BrowserCacheManager.prototype.setupBrowserStorage = function (cacheLocation) {
        switch (cacheLocation) {
            case BrowserCacheLocation.LocalStorage:
            case BrowserCacheLocation.SessionStorage:
                try {
                    // Temporary cache items will always be stored in session storage to mitigate problems caused by multiple tabs
                    return new BrowserStorage(cacheLocation);
                }
                catch (e) {
                    this.logger.verbose(e);
                    break;
                }
        }
        this.cacheConfig.cacheLocation = BrowserCacheLocation.MemoryStorage;
        return new MemoryStorage();
    };
    /**
     *
     * @param cacheLocation
     */
    BrowserCacheManager.prototype.setupTemporaryCacheStorage = function (cacheLocation) {
        switch (cacheLocation) {
            case BrowserCacheLocation.LocalStorage:
            case BrowserCacheLocation.SessionStorage:
                try {
                    // Temporary cache items will always be stored in session storage to mitigate problems caused by multiple tabs
                    return new BrowserStorage(BrowserCacheLocation.SessionStorage);
                }
                catch (e) {
                    this.logger.verbose(e);
                    return this.internalStorage;
                }
            case BrowserCacheLocation.MemoryStorage:
            default:
                return this.internalStorage;
        }
    };
    /**
     * Migrate all old cache entries to new schema. No rollback supported.
     * @param storeAuthStateInCookie
     */
    BrowserCacheManager.prototype.migrateCacheEntries = function () {
        var _this = this;
        var idTokenKey = Constants.CACHE_PREFIX + "." + PersistentCacheKeys.ID_TOKEN;
        var clientInfoKey = Constants.CACHE_PREFIX + "." + PersistentCacheKeys.CLIENT_INFO;
        var errorKey = Constants.CACHE_PREFIX + "." + PersistentCacheKeys.ERROR;
        var errorDescKey = Constants.CACHE_PREFIX + "." + PersistentCacheKeys.ERROR_DESC;
        var idTokenValue = this.browserStorage.getItem(idTokenKey);
        var clientInfoValue = this.browserStorage.getItem(clientInfoKey);
        var errorValue = this.browserStorage.getItem(errorKey);
        var errorDescValue = this.browserStorage.getItem(errorDescKey);
        var values = [idTokenValue, clientInfoValue, errorValue, errorDescValue];
        var keysToMigrate = [PersistentCacheKeys.ID_TOKEN, PersistentCacheKeys.CLIENT_INFO, PersistentCacheKeys.ERROR, PersistentCacheKeys.ERROR_DESC];
        keysToMigrate.forEach(function (cacheKey, index) { return _this.migrateCacheEntry(cacheKey, values[index]); });
    };
    /**
     * Utility function to help with migration.
     * @param newKey
     * @param value
     * @param storeAuthStateInCookie
     */
    BrowserCacheManager.prototype.migrateCacheEntry = function (newKey, value) {
        if (value) {
            this.setTemporaryCache(newKey, value, true);
        }
    };
    /**
     * Parses passed value as JSON object, JSON.parse() will throw an error.
     * @param input
     */
    BrowserCacheManager.prototype.validateAndParseJson = function (jsonValue) {
        try {
            var parsedJson = JSON.parse(jsonValue);
            /**
             * There are edge cases in which JSON.parse will successfully parse a non-valid JSON object
             * (e.g. JSON.parse will parse an escaped string into an unescaped string), so adding a type check
             * of the parsed value is necessary in order to be certain that the string represents a valid JSON object.
             *
             */
            return (parsedJson && typeof parsedJson === "object") ? parsedJson : null;
        }
        catch (error) {
            return null;
        }
    };
    /**
     * fetches the entry from the browser storage based off the key
     * @param key
     */
    BrowserCacheManager.prototype.getItem = function (key) {
        return this.browserStorage.getItem(key);
    };
    /**
     * sets the entry in the browser storage
     * @param key
     * @param value
     */
    BrowserCacheManager.prototype.setItem = function (key, value) {
        this.browserStorage.setItem(key, value);
    };
    /**
     * fetch the account entity from the platform cache
     * @param accountKey
     */
    BrowserCacheManager.prototype.getAccount = function (accountKey) {
        var account = this.getItem(accountKey);
        if (!account) {
            return null;
        }
        var parsedAccount = this.validateAndParseJson(account);
        if (!parsedAccount || !AccountEntity.isAccountEntity(parsedAccount)) {
            return null;
        }
        return CacheManager.toObject(new AccountEntity(), parsedAccount);
    };
    /**
     * set account entity in the platform cache
     * @param key
     * @param value
     */
    BrowserCacheManager.prototype.setAccount = function (account) {
        this.logger.trace("BrowserCacheManager.setAccount called");
        var key = account.generateAccountKey();
        this.setItem(key, JSON.stringify(account));
    };
    /**
     * generates idToken entity from a string
     * @param idTokenKey
     */
    BrowserCacheManager.prototype.getIdTokenCredential = function (idTokenKey) {
        var value = this.getItem(idTokenKey);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getIdTokenCredential: called, no cache hit");
            return null;
        }
        var parsedIdToken = this.validateAndParseJson(value);
        if (!parsedIdToken || !IdTokenEntity.isIdTokenEntity(parsedIdToken)) {
            this.logger.trace("BrowserCacheManager.getIdTokenCredential: called, no cache hit");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getIdTokenCredential: cache hit");
        return CacheManager.toObject(new IdTokenEntity(), parsedIdToken);
    };
    /**
     * set IdToken credential to the platform cache
     * @param idToken
     */
    BrowserCacheManager.prototype.setIdTokenCredential = function (idToken) {
        this.logger.trace("BrowserCacheManager.setIdTokenCredential called");
        var idTokenKey = idToken.generateCredentialKey();
        this.setItem(idTokenKey, JSON.stringify(idToken));
    };
    /**
     * generates accessToken entity from a string
     * @param key
     */
    BrowserCacheManager.prototype.getAccessTokenCredential = function (accessTokenKey) {
        var value = this.getItem(accessTokenKey);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getAccessTokenCredential: called, no cache hit");
            return null;
        }
        var parsedAccessToken = this.validateAndParseJson(value);
        if (!parsedAccessToken || !AccessTokenEntity.isAccessTokenEntity(parsedAccessToken)) {
            this.logger.trace("BrowserCacheManager.getAccessTokenCredential: called, no cache hit");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getAccessTokenCredential: cache hit");
        return CacheManager.toObject(new AccessTokenEntity(), parsedAccessToken);
    };
    /**
     * set accessToken credential to the platform cache
     * @param accessToken
     */
    BrowserCacheManager.prototype.setAccessTokenCredential = function (accessToken) {
        this.logger.trace("BrowserCacheManager.setAccessTokenCredential called");
        var accessTokenKey = accessToken.generateCredentialKey();
        this.setItem(accessTokenKey, JSON.stringify(accessToken));
    };
    /**
     * generates refreshToken entity from a string
     * @param refreshTokenKey
     */
    BrowserCacheManager.prototype.getRefreshTokenCredential = function (refreshTokenKey) {
        var value = this.getItem(refreshTokenKey);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getRefreshTokenCredential: called, no cache hit");
            return null;
        }
        var parsedRefreshToken = this.validateAndParseJson(value);
        if (!parsedRefreshToken || !RefreshTokenEntity.isRefreshTokenEntity(parsedRefreshToken)) {
            this.logger.trace("BrowserCacheManager.getRefreshTokenCredential: called, no cache hit");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getRefreshTokenCredential: cache hit");
        return CacheManager.toObject(new RefreshTokenEntity(), parsedRefreshToken);
    };
    /**
     * set refreshToken credential to the platform cache
     * @param refreshToken
     */
    BrowserCacheManager.prototype.setRefreshTokenCredential = function (refreshToken) {
        this.logger.trace("BrowserCacheManager.setRefreshTokenCredential called");
        var refreshTokenKey = refreshToken.generateCredentialKey();
        this.setItem(refreshTokenKey, JSON.stringify(refreshToken));
    };
    /**
     * fetch appMetadata entity from the platform cache
     * @param appMetadataKey
     */
    BrowserCacheManager.prototype.getAppMetadata = function (appMetadataKey) {
        var value = this.getItem(appMetadataKey);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getAppMetadata: called, no cache hit");
            return null;
        }
        var parsedMetadata = this.validateAndParseJson(value);
        if (!parsedMetadata || !AppMetadataEntity.isAppMetadataEntity(appMetadataKey, parsedMetadata)) {
            this.logger.trace("BrowserCacheManager.getAppMetadata: called, no cache hit");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getAppMetadata: cache hit");
        return CacheManager.toObject(new AppMetadataEntity(), parsedMetadata);
    };
    /**
     * set appMetadata entity to the platform cache
     * @param appMetadata
     */
    BrowserCacheManager.prototype.setAppMetadata = function (appMetadata) {
        this.logger.trace("BrowserCacheManager.setAppMetadata called");
        var appMetadataKey = appMetadata.generateAppMetadataKey();
        this.setItem(appMetadataKey, JSON.stringify(appMetadata));
    };
    /**
     * fetch server telemetry entity from the platform cache
     * @param serverTelemetryKey
     */
    BrowserCacheManager.prototype.getServerTelemetry = function (serverTelemetryKey) {
        var value = this.getItem(serverTelemetryKey);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getServerTelemetry: called, no cache hit");
            return null;
        }
        var parsedMetadata = this.validateAndParseJson(value);
        if (!parsedMetadata || !ServerTelemetryEntity.isServerTelemetryEntity(serverTelemetryKey, parsedMetadata)) {
            this.logger.trace("BrowserCacheManager.getServerTelemetry: called, no cache hit");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getServerTelemetry: cache hit");
        return CacheManager.toObject(new ServerTelemetryEntity(), parsedMetadata);
    };
    /**
     * set server telemetry entity to the platform cache
     * @param serverTelemetryKey
     * @param serverTelemetry
     */
    BrowserCacheManager.prototype.setServerTelemetry = function (serverTelemetryKey, serverTelemetry) {
        this.logger.trace("BrowserCacheManager.setServerTelemetry called");
        this.setItem(serverTelemetryKey, JSON.stringify(serverTelemetry));
    };
    /**
     *
     */
    BrowserCacheManager.prototype.getAuthorityMetadata = function (key) {
        var value = this.internalStorage.getItem(key);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getAuthorityMetadata: called, no cache hit");
            return null;
        }
        var parsedMetadata = this.validateAndParseJson(value);
        if (parsedMetadata && AuthorityMetadataEntity.isAuthorityMetadataEntity(key, parsedMetadata)) {
            this.logger.trace("BrowserCacheManager.getAuthorityMetadata: cache hit");
            return CacheManager.toObject(new AuthorityMetadataEntity(), parsedMetadata);
        }
        return null;
    };
    /**
     *
     */
    BrowserCacheManager.prototype.getAuthorityMetadataKeys = function () {
        var _this = this;
        var allKeys = this.internalStorage.getKeys();
        return allKeys.filter(function (key) {
            return _this.isAuthorityMetadata(key);
        });
    };
    /**
     * Sets wrapper metadata in memory
     * @param wrapperSKU
     * @param wrapperVersion
     */
    BrowserCacheManager.prototype.setWrapperMetadata = function (wrapperSKU, wrapperVersion) {
        this.internalStorage.setItem(InMemoryCacheKeys.WRAPPER_SKU, wrapperSKU);
        this.internalStorage.setItem(InMemoryCacheKeys.WRAPPER_VER, wrapperVersion);
    };
    /**
     * Returns wrapper metadata from in-memory storage
     */
    BrowserCacheManager.prototype.getWrapperMetadata = function () {
        var sku = this.internalStorage.getItem(InMemoryCacheKeys.WRAPPER_SKU) || Constants.EMPTY_STRING;
        var version = this.internalStorage.getItem(InMemoryCacheKeys.WRAPPER_VER) || Constants.EMPTY_STRING;
        return [sku, version];
    };
    /**
     *
     * @param entity
     */
    BrowserCacheManager.prototype.setAuthorityMetadata = function (key, entity) {
        this.logger.trace("BrowserCacheManager.setAuthorityMetadata called");
        this.internalStorage.setItem(key, JSON.stringify(entity));
    };
    /**
     * Gets the active account
     */
    BrowserCacheManager.prototype.getActiveAccount = function () {
        var activeAccountKeyFilters = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS);
        var activeAccountValueFilters = this.getItem(activeAccountKeyFilters);
        if (!activeAccountValueFilters) {
            // if new active account cache type isn't found, it's an old version, so look for that instead
            this.logger.trace("No active account filters cache schema found, looking for legacy schema");
            var activeAccountKeyLocal = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT);
            var activeAccountValueLocal = this.getItem(activeAccountKeyLocal);
            if (!activeAccountValueLocal) {
                this.logger.trace("No active account found");
                return null;
            }
            var activeAccount = this.getAccountInfoByFilter({ localAccountId: activeAccountValueLocal })[0] || null;
            if (activeAccount) {
                this.logger.trace("Legacy active account cache schema found");
                this.logger.trace("Adding active account filters cache schema");
                this.setActiveAccount(activeAccount);
                return activeAccount;
            }
            return null;
        }
        var activeAccountValueObj = this.validateAndParseJson(activeAccountValueFilters);
        if (activeAccountValueObj) {
            this.logger.trace("Active account filters schema found");
            return this.getAccountInfoByFilter({
                homeAccountId: activeAccountValueObj.homeAccountId,
                localAccountId: activeAccountValueObj.localAccountId
            })[0] || null;
        }
        this.logger.trace("No active account found");
        return null;
    };
    /**
     * Sets the active account's localAccountId in cache
     * @param account
     */
    BrowserCacheManager.prototype.setActiveAccount = function (account) {
        var activeAccountKey = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS);
        var activeAccountKeyLocal = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT);
        if (account) {
            this.logger.verbose("setActiveAccount: Active account set");
            var activeAccountValue = {
                homeAccountId: account.homeAccountId,
                localAccountId: account.localAccountId
            };
            this.browserStorage.setItem(activeAccountKey, JSON.stringify(activeAccountValue));
            this.browserStorage.setItem(activeAccountKeyLocal, account.localAccountId);
        }
        else {
            this.logger.verbose("setActiveAccount: No account passed, active account not set");
            this.browserStorage.removeItem(activeAccountKey);
            this.browserStorage.removeItem(activeAccountKeyLocal);
        }
    };
    /**
     * Gets a list of accounts that match all of the filters provided
     * @param account
     */
    BrowserCacheManager.prototype.getAccountInfoByFilter = function (accountFilter) {
        var allAccounts = this.getAllAccounts();
        return allAccounts.filter(function (accountObj) {
            if (accountFilter.username && accountFilter.username.toLowerCase() !== accountObj.username.toLowerCase()) {
                return false;
            }
            if (accountFilter.homeAccountId && accountFilter.homeAccountId !== accountObj.homeAccountId) {
                return false;
            }
            if (accountFilter.localAccountId && accountFilter.localAccountId !== accountObj.localAccountId) {
                return false;
            }
            if (accountFilter.tenantId && accountFilter.tenantId !== accountObj.tenantId) {
                return false;
            }
            if (accountFilter.environment && accountFilter.environment !== accountObj.environment) {
                return false;
            }
            return true;
        });
    };
    /**
     * Checks the cache for accounts matching loginHint or SID
     * @param loginHint
     * @param sid
     */
    BrowserCacheManager.prototype.getAccountInfoByHints = function (loginHint, sid) {
        var matchingAccounts = this.getAllAccounts().filter(function (accountInfo) {
            if (sid) {
                var accountSid = accountInfo.idTokenClaims && accountInfo.idTokenClaims["sid"];
                return sid === accountSid;
            }
            if (loginHint) {
                return loginHint === accountInfo.username;
            }
            return false;
        });
        if (matchingAccounts.length === 1) {
            return matchingAccounts[0];
        }
        else if (matchingAccounts.length > 1) {
            throw ClientAuthError.createMultipleMatchingAccountsInCacheError();
        }
        return null;
    };
    /**
     * fetch throttling entity from the platform cache
     * @param throttlingCacheKey
     */
    BrowserCacheManager.prototype.getThrottlingCache = function (throttlingCacheKey) {
        var value = this.getItem(throttlingCacheKey);
        if (!value) {
            this.logger.trace("BrowserCacheManager.getThrottlingCache: called, no cache hit");
            return null;
        }
        var parsedThrottlingCache = this.validateAndParseJson(value);
        if (!parsedThrottlingCache || !ThrottlingEntity.isThrottlingEntity(throttlingCacheKey, parsedThrottlingCache)) {
            this.logger.trace("BrowserCacheManager.getThrottlingCache: called, no cache hit");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getThrottlingCache: cache hit");
        return CacheManager.toObject(new ThrottlingEntity(), parsedThrottlingCache);
    };
    /**
     * set throttling entity to the platform cache
     * @param throttlingCacheKey
     * @param throttlingCache
     */
    BrowserCacheManager.prototype.setThrottlingCache = function (throttlingCacheKey, throttlingCache) {
        this.logger.trace("BrowserCacheManager.setThrottlingCache called");
        this.setItem(throttlingCacheKey, JSON.stringify(throttlingCache));
    };
    /**
     * Gets cache item with given key.
     * Will retrieve from cookies if storeAuthStateInCookie is set to true.
     * @param key
     */
    BrowserCacheManager.prototype.getTemporaryCache = function (cacheKey, generateKey) {
        var key = generateKey ? this.generateCacheKey(cacheKey) : cacheKey;
        if (this.cacheConfig.storeAuthStateInCookie) {
            var itemCookie = this.getItemCookie(key);
            if (itemCookie) {
                this.logger.trace("BrowserCacheManager.getTemporaryCache: storeAuthStateInCookies set to true, retrieving from cookies");
                return itemCookie;
            }
        }
        var value = this.temporaryCacheStorage.getItem(key);
        if (!value) {
            // If temp cache item not found in session/memory, check local storage for items set by old versions
            if (this.cacheConfig.cacheLocation === BrowserCacheLocation.LocalStorage) {
                var item = this.browserStorage.getItem(key);
                if (item) {
                    this.logger.trace("BrowserCacheManager.getTemporaryCache: Temporary cache item found in local storage");
                    return item;
                }
            }
            this.logger.trace("BrowserCacheManager.getTemporaryCache: No cache item found in local storage");
            return null;
        }
        this.logger.trace("BrowserCacheManager.getTemporaryCache: Temporary cache item returned");
        return value;
    };
    /**
     * Sets the cache item with the key and value given.
     * Stores in cookie if storeAuthStateInCookie is set to true.
     * This can cause cookie overflow if used incorrectly.
     * @param key
     * @param value
     */
    BrowserCacheManager.prototype.setTemporaryCache = function (cacheKey, value, generateKey) {
        var key = generateKey ? this.generateCacheKey(cacheKey) : cacheKey;
        this.temporaryCacheStorage.setItem(key, value);
        if (this.cacheConfig.storeAuthStateInCookie) {
            this.logger.trace("BrowserCacheManager.setTemporaryCache: storeAuthStateInCookie set to true, setting item cookie");
            this.setItemCookie(key, value);
        }
    };
    /**
     * Removes the cache item with the given key.
     * Will also clear the cookie item if storeAuthStateInCookie is set to true.
     * @param key
     */
    BrowserCacheManager.prototype.removeItem = function (key) {
        this.browserStorage.removeItem(key);
        this.temporaryCacheStorage.removeItem(key);
        if (this.cacheConfig.storeAuthStateInCookie) {
            this.logger.trace("BrowserCacheManager.removeItem: storeAuthStateInCookie is true, clearing item cookie");
            this.clearItemCookie(key);
        }
        return true;
    };
    /**
     * Checks whether key is in cache.
     * @param key
     */
    BrowserCacheManager.prototype.containsKey = function (key) {
        return this.browserStorage.containsKey(key) || this.temporaryCacheStorage.containsKey(key);
    };
    /**
     * Gets all keys in window.
     */
    BrowserCacheManager.prototype.getKeys = function () {
        return __spread(this.browserStorage.getKeys(), this.temporaryCacheStorage.getKeys());
    };
    /**
     * Clears all cache entries created by MSAL.
     */
    BrowserCacheManager.prototype.clear = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: 
                    // Removes all accounts and their credentials
                    return [4 /*yield*/, this.removeAllAccounts()];
                    case 1:
                        // Removes all accounts and their credentials
                        _a.sent();
                        this.removeAppMetadata();
                        // Removes all remaining MSAL cache items
                        this.getKeys().forEach(function (cacheKey) {
                            // Check if key contains msal prefix; For now, we are clearing all the cache items created by MSAL.js
                            if ((_this.browserStorage.containsKey(cacheKey) || _this.temporaryCacheStorage.containsKey(cacheKey)) && ((cacheKey.indexOf(Constants.CACHE_PREFIX) !== -1) || (cacheKey.indexOf(_this.clientId) !== -1))) {
                                _this.removeItem(cacheKey);
                            }
                        });
                        this.internalStorage.clear();
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Add value to cookies
     * @param cookieName
     * @param cookieValue
     * @param expires
     */
    BrowserCacheManager.prototype.setItemCookie = function (cookieName, cookieValue, expires) {
        var cookieStr = encodeURIComponent(cookieName) + "=" + encodeURIComponent(cookieValue) + ";path=/;SameSite=Lax;";
        if (expires) {
            var expireTime = this.getCookieExpirationTime(expires);
            cookieStr += "expires=" + expireTime + ";";
        }
        if (this.cacheConfig.secureCookies) {
            cookieStr += "Secure;";
        }
        document.cookie = cookieStr;
    };
    /**
     * Get one item by key from cookies
     * @param cookieName
     */
    BrowserCacheManager.prototype.getItemCookie = function (cookieName) {
        var name = encodeURIComponent(cookieName) + "=";
        var cookieList = document.cookie.split(";");
        for (var i = 0; i < cookieList.length; i++) {
            var cookie = cookieList[i];
            while (cookie.charAt(0) === " ") {
                cookie = cookie.substring(1);
            }
            if (cookie.indexOf(name) === 0) {
                return decodeURIComponent(cookie.substring(name.length, cookie.length));
            }
        }
        return Constants.EMPTY_STRING;
    };
    /**
     * Clear all msal-related cookies currently set in the browser. Should only be used to clear temporary cache items.
     */
    BrowserCacheManager.prototype.clearMsalCookies = function () {
        var _this = this;
        var cookiePrefix = Constants.CACHE_PREFIX + "." + this.clientId;
        var cookieList = document.cookie.split(";");
        cookieList.forEach(function (cookie) {
            while (cookie.charAt(0) === " ") {
                // eslint-disable-next-line no-param-reassign
                cookie = cookie.substring(1);
            }
            if (cookie.indexOf(cookiePrefix) === 0) {
                var cookieKey = cookie.split("=")[0];
                _this.clearItemCookie(cookieKey);
            }
        });
    };
    /**
     * Clear an item in the cookies by key
     * @param cookieName
     */
    BrowserCacheManager.prototype.clearItemCookie = function (cookieName) {
        this.setItemCookie(cookieName, Constants.EMPTY_STRING, -1);
    };
    /**
     * Get cookie expiration time
     * @param cookieLifeDays
     */
    BrowserCacheManager.prototype.getCookieExpirationTime = function (cookieLifeDays) {
        var today = new Date();
        var expr = new Date(today.getTime() + cookieLifeDays * this.COOKIE_LIFE_MULTIPLIER);
        return expr.toUTCString();
    };
    /**
     * Gets the cache object referenced by the browser
     */
    BrowserCacheManager.prototype.getCache = function () {
        return this.browserStorage;
    };
    /**
     * interface compat, we cannot overwrite browser cache; Functionality is supported by individual entities in browser
     */
    BrowserCacheManager.prototype.setCache = function () {
        // sets nothing
    };
    /**
     * Prepend msal.<client-id> to each key; Skip for any JSON object as Key (defined schemas do not need the key appended: AccessToken Keys or the upcoming schema)
     * @param key
     * @param addInstanceId
     */
    BrowserCacheManager.prototype.generateCacheKey = function (key) {
        var generatedKey = this.validateAndParseJson(key);
        if (!generatedKey) {
            if (StringUtils.startsWith(key, Constants.CACHE_PREFIX) || StringUtils.startsWith(key, PersistentCacheKeys.ADAL_ID_TOKEN)) {
                return key;
            }
            return Constants.CACHE_PREFIX + "." + this.clientId + "." + key;
        }
        return JSON.stringify(key);
    };
    /**
     * Create authorityKey to cache authority
     * @param state
     */
    BrowserCacheManager.prototype.generateAuthorityKey = function (stateString) {
        var stateId = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString).libraryState.id;
        return this.generateCacheKey(TemporaryCacheKeys.AUTHORITY + "." + stateId);
    };
    /**
     * Create Nonce key to cache nonce
     * @param state
     */
    BrowserCacheManager.prototype.generateNonceKey = function (stateString) {
        var stateId = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString).libraryState.id;
        return this.generateCacheKey(TemporaryCacheKeys.NONCE_IDTOKEN + "." + stateId);
    };
    /**
     * Creates full cache key for the request state
     * @param stateString State string for the request
     */
    BrowserCacheManager.prototype.generateStateKey = function (stateString) {
        // Use the library state id to key temp storage for uniqueness for multiple concurrent requests
        var stateId = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString).libraryState.id;
        return this.generateCacheKey(TemporaryCacheKeys.REQUEST_STATE + "." + stateId);
    };
    /**
     * Gets the cached authority based on the cached state. Returns empty if no cached state found.
     */
    BrowserCacheManager.prototype.getCachedAuthority = function (cachedState) {
        var stateCacheKey = this.generateStateKey(cachedState);
        var state = this.getTemporaryCache(stateCacheKey);
        if (!state) {
            return null;
        }
        var authorityCacheKey = this.generateAuthorityKey(state);
        return this.getTemporaryCache(authorityCacheKey);
    };
    /**
     * Updates account, authority, and state in cache
     * @param serverAuthenticationRequest
     * @param account
     */
    BrowserCacheManager.prototype.updateCacheEntries = function (state, nonce, authorityInstance, loginHint, account) {
        this.logger.trace("BrowserCacheManager.updateCacheEntries called");
        // Cache the request state
        var stateCacheKey = this.generateStateKey(state);
        this.setTemporaryCache(stateCacheKey, state, false);
        // Cache the nonce
        var nonceCacheKey = this.generateNonceKey(state);
        this.setTemporaryCache(nonceCacheKey, nonce, false);
        // Cache authorityKey
        var authorityCacheKey = this.generateAuthorityKey(state);
        this.setTemporaryCache(authorityCacheKey, authorityInstance, false);
        if (account) {
            var ccsCredential = {
                credential: account.homeAccountId,
                type: CcsCredentialType.HOME_ACCOUNT_ID
            };
            this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
        }
        else if (!StringUtils.isEmpty(loginHint)) {
            var ccsCredential = {
                credential: loginHint,
                type: CcsCredentialType.UPN
            };
            this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
        }
    };
    /**
     * Reset all temporary cache items
     * @param state
     */
    BrowserCacheManager.prototype.resetRequestCache = function (state) {
        var _this = this;
        this.logger.trace("BrowserCacheManager.resetRequestCache called");
        // check state and remove associated cache items
        if (!StringUtils.isEmpty(state)) {
            this.getKeys().forEach(function (key) {
                if (key.indexOf(state) !== -1) {
                    _this.removeItem(key);
                }
            });
        }
        // delete generic interactive request parameters
        if (state) {
            this.removeItem(this.generateStateKey(state));
            this.removeItem(this.generateNonceKey(state));
            this.removeItem(this.generateAuthorityKey(state));
        }
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.ORIGIN_URI));
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.URL_HASH));
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.CORRELATION_ID));
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.CCS_CREDENTIAL));
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
        this.setInteractionInProgress(false);
    };
    /**
     * Removes temporary cache for the provided state
     * @param stateString
     */
    BrowserCacheManager.prototype.cleanRequestByState = function (stateString) {
        this.logger.trace("BrowserCacheManager.cleanRequestByState called");
        // Interaction is completed - remove interaction status.
        if (stateString) {
            var stateKey = this.generateStateKey(stateString);
            var cachedState = this.temporaryCacheStorage.getItem(stateKey);
            this.logger.infoPii("BrowserCacheManager.cleanRequestByState: Removing temporary cache items for state: " + cachedState);
            this.resetRequestCache(cachedState || Constants.EMPTY_STRING);
        }
        this.clearMsalCookies();
    };
    /**
     * Looks in temporary cache for any state values with the provided interactionType and removes all temporary cache items for that state
     * Used in scenarios where temp cache needs to be cleaned but state is not known, such as clicking browser back button.
     * @param interactionType
     */
    BrowserCacheManager.prototype.cleanRequestByInteractionType = function (interactionType) {
        var _this = this;
        this.logger.trace("BrowserCacheManager.cleanRequestByInteractionType called");
        // Loop through all keys to find state key
        this.getKeys().forEach(function (key) {
            // If this key is not the state key, move on
            if (key.indexOf(TemporaryCacheKeys.REQUEST_STATE) === -1) {
                return;
            }
            // Retrieve state value, return if not a valid value
            var stateValue = _this.temporaryCacheStorage.getItem(key);
            if (!stateValue) {
                return;
            }
            // Extract state and ensure it matches given InteractionType, then clean request cache
            var parsedState = BrowserProtocolUtils.extractBrowserRequestState(_this.cryptoImpl, stateValue);
            if (parsedState && parsedState.interactionType === interactionType) {
                _this.logger.infoPii("BrowserCacheManager.cleanRequestByInteractionType: Removing temporary cache items for state: " + stateValue);
                _this.resetRequestCache(stateValue);
            }
        });
        this.clearMsalCookies();
        this.setInteractionInProgress(false);
    };
    BrowserCacheManager.prototype.cacheCodeRequest = function (authCodeRequest, browserCrypto) {
        this.logger.trace("BrowserCacheManager.cacheCodeRequest called");
        var encodedValue = browserCrypto.base64Encode(JSON.stringify(authCodeRequest));
        this.setTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, encodedValue, true);
    };
    /**
     * Gets the token exchange parameters from the cache. Throws an error if nothing is found.
     */
    BrowserCacheManager.prototype.getCachedRequest = function (state, browserCrypto) {
        this.logger.trace("BrowserCacheManager.getCachedRequest called");
        // Get token request from cache and parse as TokenExchangeParameters.
        var encodedTokenRequest = this.getTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, true);
        if (!encodedTokenRequest) {
            throw BrowserAuthError.createNoTokenRequestCacheError();
        }
        var parsedRequest = this.validateAndParseJson(browserCrypto.base64Decode(encodedTokenRequest));
        if (!parsedRequest) {
            throw BrowserAuthError.createUnableToParseTokenRequestCacheError();
        }
        this.removeItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
        // Get cached authority and use if no authority is cached with request.
        if (StringUtils.isEmpty(parsedRequest.authority)) {
            var authorityCacheKey = this.generateAuthorityKey(state);
            var cachedAuthority = this.getTemporaryCache(authorityCacheKey);
            if (!cachedAuthority) {
                throw BrowserAuthError.createNoCachedAuthorityError();
            }
            parsedRequest.authority = cachedAuthority;
        }
        return parsedRequest;
    };
    /**
     * Gets cached native request for redirect flows
     */
    BrowserCacheManager.prototype.getCachedNativeRequest = function () {
        this.logger.trace("BrowserCacheManager.getCachedNativeRequest called");
        var cachedRequest = this.getTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, true);
        if (!cachedRequest) {
            this.logger.trace("BrowserCacheManager.getCachedNativeRequest: No cached native request found");
            return null;
        }
        var parsedRequest = this.validateAndParseJson(cachedRequest);
        if (!parsedRequest) {
            this.logger.error("BrowserCacheManager.getCachedNativeRequest: Unable to parse native request");
            return null;
        }
        return parsedRequest;
    };
    BrowserCacheManager.prototype.isInteractionInProgress = function (matchClientId) {
        var clientId = this.getInteractionInProgress();
        if (matchClientId) {
            return clientId === this.clientId;
        }
        else {
            return !!clientId;
        }
    };
    BrowserCacheManager.prototype.getInteractionInProgress = function () {
        var key = Constants.CACHE_PREFIX + "." + TemporaryCacheKeys.INTERACTION_STATUS_KEY;
        return this.getTemporaryCache(key, false);
    };
    BrowserCacheManager.prototype.setInteractionInProgress = function (inProgress) {
        // Ensure we don't overwrite interaction in progress for a different clientId
        var key = Constants.CACHE_PREFIX + "." + TemporaryCacheKeys.INTERACTION_STATUS_KEY;
        if (inProgress) {
            if (this.getInteractionInProgress()) {
                throw BrowserAuthError.createInteractionInProgressError();
            }
            else {
                // No interaction is in progress
                this.setTemporaryCache(key, this.clientId, false);
            }
        }
        else if (!inProgress && this.getInteractionInProgress() === this.clientId) {
            this.removeItem(key);
        }
    };
    /**
     * Returns username retrieved from ADAL or MSAL v1 idToken
     */
    BrowserCacheManager.prototype.getLegacyLoginHint = function () {
        // Only check for adal/msal token if no SSO params are being used
        var adalIdTokenString = this.getTemporaryCache(PersistentCacheKeys.ADAL_ID_TOKEN);
        if (adalIdTokenString) {
            this.browserStorage.removeItem(PersistentCacheKeys.ADAL_ID_TOKEN);
            this.logger.verbose("Cached ADAL id token retrieved.");
        }
        // Check for cached MSAL v1 id token
        var msalIdTokenString = this.getTemporaryCache(PersistentCacheKeys.ID_TOKEN, true);
        if (msalIdTokenString) {
            this.removeItem(this.generateCacheKey(PersistentCacheKeys.ID_TOKEN));
            this.logger.verbose("Cached MSAL.js v1 id token retrieved");
        }
        var cachedIdTokenString = msalIdTokenString || adalIdTokenString;
        if (cachedIdTokenString) {
            var cachedIdToken = new IdToken(cachedIdTokenString, this.cryptoImpl);
            if (cachedIdToken.claims && cachedIdToken.claims.preferred_username) {
                this.logger.verbose("No SSO params used and ADAL/MSAL v1 token retrieved, setting ADAL/MSAL v1 preferred_username as loginHint");
                return cachedIdToken.claims.preferred_username;
            }
            else if (cachedIdToken.claims && cachedIdToken.claims.upn) {
                this.logger.verbose("No SSO params used and ADAL/MSAL v1 token retrieved, setting ADAL/MSAL v1 upn as loginHint");
                return cachedIdToken.claims.upn;
            }
            else {
                this.logger.verbose("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.");
            }
        }
        return null;
    };
    /**
     * Updates a credential's cache key if the current cache key is outdated
     */
    BrowserCacheManager.prototype.updateCredentialCacheKey = function (currentCacheKey, credential) {
        var updatedCacheKey = credential.generateCredentialKey();
        if (currentCacheKey !== updatedCacheKey) {
            var cacheItem = this.getItem(currentCacheKey);
            if (cacheItem) {
                this.removeItem(currentCacheKey);
                this.setItem(updatedCacheKey, cacheItem);
                this.logger.verbose("Updated an outdated " + credential.credentialType + " cache key");
                return updatedCacheKey;
            }
            else {
                this.logger.error("Attempted to update an outdated " + credential.credentialType + " cache key but no item matching the outdated key was found in storage");
            }
        }
        return currentCacheKey;
    };
    return BrowserCacheManager;
}(CacheManager));
var DEFAULT_BROWSER_CACHE_MANAGER = function (clientId, logger) {
    var cacheOptions = {
        cacheLocation: BrowserCacheLocation.MemoryStorage,
        storeAuthStateInCookie: false,
        secureCookies: false
    };
    return new BrowserCacheManager(clientId, cacheOptions, DEFAULT_CRYPTO_IMPLEMENTATION, logger);
};

export { BrowserCacheManager, DEFAULT_BROWSER_CACHE_MANAGER };
//# sourceMappingURL=BrowserCacheManager.js.map
