/*! @azure/msal-common v12.0.0 2023-04-03 */
'use strict';
import { __awaiter, __generator, __assign, __extends } from '../_virtual/_tslib.js';
import { Separators, CredentialType, AuthenticationScheme, THE_FAMILY_ID, APP_METADATA, AUTHORITY_METADATA_CONSTANTS } from '../utils/Constants.js';
import { ScopeSet } from '../request/ScopeSet.js';
import { AccountEntity } from './entities/AccountEntity.js';
import { AuthError } from '../error/AuthError.js';
import { ClientAuthError } from '../error/ClientAuthError.js';
import { AuthToken } from '../account/AuthToken.js';
import { name, version } from '../packageMetadata.js';

/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
/**
 * Interface class which implement cache storage functions used by MSAL to perform validity checks, and store tokens.
 */
var CacheManager = /** @class */ (function () {
    function CacheManager(clientId, cryptoImpl, logger) {
        this.clientId = clientId;
        this.cryptoImpl = cryptoImpl;
        this.commonLogger = logger.clone(name, version);
    }
    /**
     * Returns all accounts in cache
     */
    CacheManager.prototype.getAllAccounts = function () {
        var _this = this;
        var allAccountKeys = this.getAccountKeys();
        if (allAccountKeys.length < 1) {
            return [];
        }
        var accountEntities = allAccountKeys.reduce(function (accounts, key) {
            var entity = _this.getAccount(key);
            if (!entity) {
                return accounts;
            }
            accounts.push(entity);
            return accounts;
        }, []);
        if (accountEntities.length < 1) {
            return [];
        }
        else {
            var allAccounts = accountEntities.map(function (accountEntity) {
                return _this.getAccountInfoFromEntity(accountEntity);
            });
            return allAccounts;
        }
    };
    /**
     * Gets accountInfo object based on provided filters
     */
    CacheManager.prototype.getAccountInfoFilteredBy = function (accountFilter) {
        var allAccounts = this.getAccountsFilteredBy(accountFilter);
        if (allAccounts.length > 0) {
            return this.getAccountInfoFromEntity(allAccounts[0]);
        }
        else {
            return null;
        }
    };
    CacheManager.prototype.getAccountInfoFromEntity = function (accountEntity) {
        var accountInfo = accountEntity.getAccountInfo();
        var idToken = this.getIdToken(accountInfo);
        if (idToken) {
            accountInfo.idToken = idToken.secret;
            accountInfo.idTokenClaims = new AuthToken(idToken.secret, this.cryptoImpl).claims;
        }
        return accountInfo;
    };
    /**
     * saves a cache record
     * @param cacheRecord
     */
    CacheManager.prototype.saveCacheRecord = function (cacheRecord) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!cacheRecord) {
                            throw ClientAuthError.createNullOrUndefinedCacheRecord();
                        }
                        if (!!cacheRecord.account) {
                            this.setAccount(cacheRecord.account);
                        }
                        if (!!cacheRecord.idToken) {
                            this.setIdTokenCredential(cacheRecord.idToken);
                        }
                        if (!!!cacheRecord.accessToken) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.saveAccessToken(cacheRecord.accessToken)];
                    case 1:
                        _a.sent();
                        _a.label = 2;
                    case 2:
                        if (!!cacheRecord.refreshToken) {
                            this.setRefreshTokenCredential(cacheRecord.refreshToken);
                        }
                        if (!!cacheRecord.appMetadata) {
                            this.setAppMetadata(cacheRecord.appMetadata);
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * saves access token credential
     * @param credential
     */
    CacheManager.prototype.saveAccessToken = function (credential) {
        return __awaiter(this, void 0, void 0, function () {
            var accessTokenFilter, tokenKeys, currentScopes, removedAccessTokens;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        accessTokenFilter = {
                            clientId: credential.clientId,
                            credentialType: credential.credentialType,
                            environment: credential.environment,
                            homeAccountId: credential.homeAccountId,
                            realm: credential.realm,
                            tokenType: credential.tokenType,
                            requestedClaimsHash: credential.requestedClaimsHash
                        };
                        tokenKeys = this.getTokenKeys();
                        currentScopes = ScopeSet.fromString(credential.target);
                        removedAccessTokens = [];
                        tokenKeys.accessToken.forEach(function (key) {
                            if (!_this.accessTokenKeyMatchesFilter(key, accessTokenFilter, false)) {
                                return;
                            }
                            var tokenEntity = _this.getAccessTokenCredential(key);
                            if (tokenEntity && _this.credentialMatchesFilter(tokenEntity, accessTokenFilter)) {
                                var tokenScopeSet = ScopeSet.fromString(tokenEntity.target);
                                if (tokenScopeSet.intersectingScopeSets(currentScopes)) {
                                    removedAccessTokens.push(_this.removeAccessToken(key));
                                }
                            }
                        });
                        return [4 /*yield*/, Promise.all(removedAccessTokens)];
                    case 1:
                        _a.sent();
                        this.setAccessTokenCredential(credential);
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * retrieve accounts matching all provided filters; if no filter is set, get all accounts
     * not checking for casing as keys are all generated in lower case, remember to convert to lower case if object properties are compared
     * @param homeAccountId
     * @param environment
     * @param realm
     */
    CacheManager.prototype.getAccountsFilteredBy = function (accountFilter) {
        var _this = this;
        var allAccountKeys = this.getAccountKeys();
        var matchingAccounts = [];
        allAccountKeys.forEach(function (cacheKey) {
            if (!_this.isAccountKey(cacheKey, accountFilter.homeAccountId, accountFilter.realm)) {
                // Don't parse value if the key doesn't match the account filters
                return;
            }
            var entity = _this.getAccount(cacheKey);
            if (!entity) {
                return;
            }
            if (!!accountFilter.homeAccountId && !_this.matchHomeAccountId(entity, accountFilter.homeAccountId)) {
                return;
            }
            if (!!accountFilter.localAccountId && !_this.matchLocalAccountId(entity, accountFilter.localAccountId)) {
                return;
            }
            if (!!accountFilter.username && !_this.matchUsername(entity, accountFilter.username)) {
                return;
            }
            if (!!accountFilter.environment && !_this.matchEnvironment(entity, accountFilter.environment)) {
                return;
            }
            if (!!accountFilter.realm && !_this.matchRealm(entity, accountFilter.realm)) {
                return;
            }
            if (!!accountFilter.nativeAccountId && !_this.matchNativeAccountId(entity, accountFilter.nativeAccountId)) {
                return;
            }
            matchingAccounts.push(entity);
        });
        return matchingAccounts;
    };
    /**
     * Returns true if the given key matches our account key schema. Also matches homeAccountId and/or tenantId if provided
     * @param key
     * @param homeAccountId
     * @param tenantId
     * @returns
     */
    CacheManager.prototype.isAccountKey = function (key, homeAccountId, tenantId) {
        if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 3) {
            // Account cache keys contain 3 items separated by '-' (each item may also contain '-')
            return false;
        }
        if (homeAccountId && !key.toLowerCase().includes(homeAccountId.toLowerCase())) {
            return false;
        }
        if (tenantId && !key.toLowerCase().includes(tenantId.toLowerCase())) {
            return false;
        }
        // Do not check environment as aliasing can cause false negatives
        return true;
    };
    /**
     * Returns true if the given key matches our credential key schema.
     * @param key
     */
    CacheManager.prototype.isCredentialKey = function (key) {
        if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 6) {
            // Credential cache keys contain 6 items separated by '-' (each item may also contain '-')
            return false;
        }
        var lowerCaseKey = key.toLowerCase();
        // Credential keys must indicate what credential type they represent
        if (lowerCaseKey.indexOf(CredentialType.ID_TOKEN.toLowerCase()) === -1 &&
            lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN.toLowerCase()) === -1 &&
            lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase()) === -1 &&
            lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) === -1) {
            return false;
        }
        if (lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) > -1) {
            // Refresh tokens must contain the client id or family id
            var clientIdValidation = "" + CredentialType.REFRESH_TOKEN + Separators.CACHE_KEY_SEPARATOR + this.clientId + Separators.CACHE_KEY_SEPARATOR;
            var familyIdValidation = "" + CredentialType.REFRESH_TOKEN + Separators.CACHE_KEY_SEPARATOR + THE_FAMILY_ID + Separators.CACHE_KEY_SEPARATOR;
            if (lowerCaseKey.indexOf(clientIdValidation.toLowerCase()) === -1 && lowerCaseKey.indexOf(familyIdValidation.toLowerCase()) === -1) {
                return false;
            }
        }
        else if (lowerCaseKey.indexOf(this.clientId.toLowerCase()) === -1) {
            // Tokens must contain the clientId
            return false;
        }
        return true;
    };
    /**
     * Returns whether or not the given credential entity matches the filter
     * @param entity
     * @param filter
     * @returns
     */
    CacheManager.prototype.credentialMatchesFilter = function (entity, filter) {
        if (!!filter.clientId && !this.matchClientId(entity, filter.clientId)) {
            return false;
        }
        if (!!filter.userAssertionHash && !this.matchUserAssertionHash(entity, filter.userAssertionHash)) {
            return false;
        }
        /*
         * homeAccountId can be undefined, and we want to filter out cached items that have a homeAccountId of ""
         * because we don't want a client_credential request to return a cached token that has a homeAccountId
         */
        if ((typeof filter.homeAccountId === "string") && !this.matchHomeAccountId(entity, filter.homeAccountId)) {
            return false;
        }
        if (!!filter.environment && !this.matchEnvironment(entity, filter.environment)) {
            return false;
        }
        if (!!filter.realm && !this.matchRealm(entity, filter.realm)) {
            return false;
        }
        if (!!filter.credentialType && !this.matchCredentialType(entity, filter.credentialType)) {
            return false;
        }
        if (!!filter.familyId && !this.matchFamilyId(entity, filter.familyId)) {
            return false;
        }
        /*
         * idTokens do not have "target", target specific refreshTokens do exist for some types of authentication
         * Resource specific refresh tokens case will be added when the support is deemed necessary
         */
        if (!!filter.target && !this.matchTarget(entity, filter.target)) {
            return false;
        }
        // If request OR cached entity has requested Claims Hash, check if they match
        if (filter.requestedClaimsHash || entity.requestedClaimsHash) {
            // Don't match if either is undefined or they are different
            if (entity.requestedClaimsHash !== filter.requestedClaimsHash) {
                return false;
            }
        }
        // Access Token with Auth Scheme specific matching
        if (entity.credentialType === CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME) {
            if (!!filter.tokenType && !this.matchTokenType(entity, filter.tokenType)) {
                return false;
            }
            // KeyId (sshKid) in request must match cached SSH certificate keyId because SSH cert is bound to a specific key
            if (filter.tokenType === AuthenticationScheme.SSH) {
                if (filter.keyId && !this.matchKeyId(entity, filter.keyId)) {
                    return false;
                }
            }
        }
        return true;
    };
    /**
     * retrieve appMetadata matching all provided filters; if no filter is set, get all appMetadata
     * @param filter
     */
    CacheManager.prototype.getAppMetadataFilteredBy = function (filter) {
        return this.getAppMetadataFilteredByInternal(filter.environment, filter.clientId);
    };
    /**
     * Support function to help match appMetadata
     * @param environment
     * @param clientId
     */
    CacheManager.prototype.getAppMetadataFilteredByInternal = function (environment, clientId) {
        var _this = this;
        var allCacheKeys = this.getKeys();
        var matchingAppMetadata = {};
        allCacheKeys.forEach(function (cacheKey) {
            // don't parse any non-appMetadata type cache entities
            if (!_this.isAppMetadata(cacheKey)) {
                return;
            }
            // Attempt retrieval
            var entity = _this.getAppMetadata(cacheKey);
            if (!entity) {
                return;
            }
            if (!!environment && !_this.matchEnvironment(entity, environment)) {
                return;
            }
            if (!!clientId && !_this.matchClientId(entity, clientId)) {
                return;
            }
            matchingAppMetadata[cacheKey] = entity;
        });
        return matchingAppMetadata;
    };
    /**
     * retrieve authorityMetadata that contains a matching alias
     * @param filter
     */
    CacheManager.prototype.getAuthorityMetadataByAlias = function (host) {
        var _this = this;
        var allCacheKeys = this.getAuthorityMetadataKeys();
        var matchedEntity = null;
        allCacheKeys.forEach(function (cacheKey) {
            // don't parse any non-authorityMetadata type cache entities
            if (!_this.isAuthorityMetadata(cacheKey) || cacheKey.indexOf(_this.clientId) === -1) {
                return;
            }
            // Attempt retrieval
            var entity = _this.getAuthorityMetadata(cacheKey);
            if (!entity) {
                return;
            }
            if (entity.aliases.indexOf(host) === -1) {
                return;
            }
            matchedEntity = entity;
        });
        return matchedEntity;
    };
    /**
     * Removes all accounts and related tokens from cache.
     */
    CacheManager.prototype.removeAllAccounts = function () {
        return __awaiter(this, void 0, void 0, function () {
            var allAccountKeys, removedAccounts;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        allAccountKeys = this.getAccountKeys();
                        removedAccounts = [];
                        allAccountKeys.forEach(function (cacheKey) {
                            removedAccounts.push(_this.removeAccount(cacheKey));
                        });
                        return [4 /*yield*/, Promise.all(removedAccounts)];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Removes the account and related tokens for a given account key
     * @param account
     */
    CacheManager.prototype.removeAccount = function (accountKey) {
        return __awaiter(this, void 0, void 0, function () {
            var account;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        account = this.getAccount(accountKey);
                        if (!account) {
                            throw ClientAuthError.createNoAccountFoundError();
                        }
                        return [4 /*yield*/, this.removeAccountContext(account)];
                    case 1:
                        _a.sent();
                        this.removeItem(accountKey);
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Removes credentials associated with the provided account
     * @param account
     */
    CacheManager.prototype.removeAccountContext = function (account) {
        return __awaiter(this, void 0, void 0, function () {
            var allTokenKeys, accountId, removedCredentials;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        allTokenKeys = this.getTokenKeys();
                        accountId = account.generateAccountId();
                        removedCredentials = [];
                        allTokenKeys.idToken.forEach(function (key) {
                            if (key.indexOf(accountId) === 0) {
                                _this.removeIdToken(key);
                            }
                        });
                        allTokenKeys.accessToken.forEach(function (key) {
                            if (key.indexOf(accountId) === 0) {
                                removedCredentials.push(_this.removeAccessToken(key));
                            }
                        });
                        allTokenKeys.refreshToken.forEach(function (key) {
                            if (key.indexOf(accountId) === 0) {
                                _this.removeRefreshToken(key);
                            }
                        });
                        return [4 /*yield*/, Promise.all(removedCredentials)];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * returns a boolean if the given credential is removed
     * @param credential
     */
    CacheManager.prototype.removeAccessToken = function (key) {
        return __awaiter(this, void 0, void 0, function () {
            var credential, accessTokenWithAuthSchemeEntity, kid;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        credential = this.getAccessTokenCredential(key);
                        if (!credential) {
                            return [2 /*return*/];
                        }
                        if (!(credential.credentialType.toLowerCase() === CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase())) return [3 /*break*/, 4];
                        if (!(credential.tokenType === AuthenticationScheme.POP)) return [3 /*break*/, 4];
                        accessTokenWithAuthSchemeEntity = credential;
                        kid = accessTokenWithAuthSchemeEntity.keyId;
                        if (!kid) return [3 /*break*/, 4];
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, this.cryptoImpl.removeTokenBindingKey(kid)];
                    case 2:
                        _a.sent();
                        return [3 /*break*/, 4];
                    case 3:
                        _a.sent();
                        throw ClientAuthError.createBindingKeyNotRemovedError();
                    case 4: return [2 /*return*/, this.removeItem(key)];
                }
            });
        });
    };
    /**
     * Removes all app metadata objects from cache.
     */
    CacheManager.prototype.removeAppMetadata = function () {
        var _this = this;
        var allCacheKeys = this.getKeys();
        allCacheKeys.forEach(function (cacheKey) {
            if (_this.isAppMetadata(cacheKey)) {
                _this.removeItem(cacheKey);
            }
        });
        return true;
    };
    /**
     * Retrieve the cached credentials into a cacherecord
     * @param account
     * @param clientId
     * @param scopes
     * @param environment
     * @param authScheme
     */
    CacheManager.prototype.readCacheRecord = function (account, request, environment) {
        var tokenKeys = this.getTokenKeys();
        var cachedAccount = this.readAccountFromCache(account);
        var cachedIdToken = this.getIdToken(account, tokenKeys);
        var cachedAccessToken = this.getAccessToken(account, request, tokenKeys);
        var cachedRefreshToken = this.getRefreshToken(account, false, tokenKeys);
        var cachedAppMetadata = this.readAppMetadataFromCache(environment);
        if (cachedAccount && cachedIdToken) {
            cachedAccount.idTokenClaims = new AuthToken(cachedIdToken.secret, this.cryptoImpl).claims;
        }
        return {
            account: cachedAccount,
            idToken: cachedIdToken,
            accessToken: cachedAccessToken,
            refreshToken: cachedRefreshToken,
            appMetadata: cachedAppMetadata,
        };
    };
    /**
     * Retrieve AccountEntity from cache
     * @param account
     */
    CacheManager.prototype.readAccountFromCache = function (account) {
        var accountKey = AccountEntity.generateAccountCacheKey(account);
        return this.getAccount(accountKey);
    };
    /**
     * Retrieve IdTokenEntity from cache
     * @param clientId
     * @param account
     * @param inputRealm
     */
    CacheManager.prototype.getIdToken = function (account, tokenKeys) {
        this.commonLogger.trace("CacheManager - getIdToken called");
        var idTokenFilter = {
            homeAccountId: account.homeAccountId,
            environment: account.environment,
            credentialType: CredentialType.ID_TOKEN,
            clientId: this.clientId,
            realm: account.tenantId,
        };
        var idTokens = this.getIdTokensByFilter(idTokenFilter, tokenKeys);
        var numIdTokens = idTokens.length;
        if (numIdTokens < 1) {
            this.commonLogger.info("CacheManager:getIdToken - No token found");
            return null;
        }
        else if (numIdTokens > 1) {
            throw ClientAuthError.createMultipleMatchingTokensInCacheError();
        }
        this.commonLogger.info("CacheManager:getIdToken - Returning id token");
        return idTokens[0];
    };
    /**
     * Gets all idTokens matching the given filter
     * @param filter
     * @returns
     */
    CacheManager.prototype.getIdTokensByFilter = function (filter, tokenKeys) {
        var _this = this;
        var idTokenKeys = tokenKeys && tokenKeys.idToken || this.getTokenKeys().idToken;
        var idTokens = [];
        idTokenKeys.forEach(function (key) {
            if (!_this.idTokenKeyMatchesFilter(key, __assign({ clientId: _this.clientId }, filter))) {
                return;
            }
            var idToken = _this.getIdTokenCredential(key);
            if (idToken && _this.credentialMatchesFilter(idToken, filter)) {
                idTokens.push(idToken);
            }
        });
        return idTokens;
    };
    /**
     * Validate the cache key against filter before retrieving and parsing cache value
     * @param key
     * @param filter
     * @returns
     */
    CacheManager.prototype.idTokenKeyMatchesFilter = function (inputKey, filter) {
        var key = inputKey.toLowerCase();
        if (filter.clientId && key.indexOf(filter.clientId.toLowerCase()) === -1) {
            return false;
        }
        if (filter.homeAccountId && key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
            return false;
        }
        return true;
    };
    /**
     * Removes idToken from the cache
     * @param key
     */
    CacheManager.prototype.removeIdToken = function (key) {
        this.removeItem(key);
    };
    /**
     * Removes refresh token from the cache
     * @param key
     */
    CacheManager.prototype.removeRefreshToken = function (key) {
        this.removeItem(key);
    };
    /**
     * Retrieve AccessTokenEntity from cache
     * @param clientId
     * @param account
     * @param scopes
     * @param authScheme
     */
    CacheManager.prototype.getAccessToken = function (account, request, tokenKeys) {
        var _this = this;
        this.commonLogger.trace("CacheManager - getAccessToken called");
        var scopes = ScopeSet.createSearchScopes(request.scopes);
        var authScheme = request.authenticationScheme || AuthenticationScheme.BEARER;
        /*
         * Distinguish between Bearer and PoP/SSH token cache types
         * Cast to lowercase to handle "bearer" from ADFS
         */
        var credentialType = (authScheme && authScheme.toLowerCase() !== AuthenticationScheme.BEARER.toLowerCase()) ? CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME : CredentialType.ACCESS_TOKEN;
        var accessTokenFilter = {
            homeAccountId: account.homeAccountId,
            environment: account.environment,
            credentialType: credentialType,
            clientId: this.clientId,
            realm: account.tenantId,
            target: scopes,
            tokenType: authScheme,
            keyId: request.sshKid,
            requestedClaimsHash: request.requestedClaimsHash,
        };
        var accessTokenKeys = tokenKeys && tokenKeys.accessToken || this.getTokenKeys().accessToken;
        var accessTokens = [];
        accessTokenKeys.forEach(function (key) {
            // Validate key
            if (_this.accessTokenKeyMatchesFilter(key, accessTokenFilter, true)) {
                var accessToken = _this.getAccessTokenCredential(key);
                // Validate value
                if (accessToken && _this.credentialMatchesFilter(accessToken, accessTokenFilter)) {
                    accessTokens.push(accessToken);
                }
            }
        });
        var numAccessTokens = accessTokens.length;
        if (numAccessTokens < 1) {
            this.commonLogger.info("CacheManager:getAccessToken - No token found");
            return null;
        }
        else if (numAccessTokens > 1) {
            throw ClientAuthError.createMultipleMatchingTokensInCacheError();
        }
        this.commonLogger.info("CacheManager:getAccessToken - Returning access token");
        return accessTokens[0];
    };
    /**
     * Validate the cache key against filter before retrieving and parsing cache value
     * @param key
     * @param filter
     * @param keyMustContainAllScopes
     * @returns
     */
    CacheManager.prototype.accessTokenKeyMatchesFilter = function (inputKey, filter, keyMustContainAllScopes) {
        var key = inputKey.toLowerCase();
        if (filter.clientId && key.indexOf(filter.clientId.toLowerCase()) === -1) {
            return false;
        }
        if (filter.homeAccountId && key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
            return false;
        }
        if (filter.realm && key.indexOf(filter.realm.toLowerCase()) === -1) {
            return false;
        }
        if (filter.requestedClaimsHash && key.indexOf(filter.requestedClaimsHash.toLowerCase()) === -1) {
            return false;
        }
        if (filter.target) {
            var scopes = filter.target.asArray();
            for (var i = 0; i < scopes.length; i++) {
                if (keyMustContainAllScopes && !key.includes(scopes[i].toLowerCase())) {
                    // When performing a cache lookup a missing scope would be a cache miss
                    return false;
                }
                else if (!keyMustContainAllScopes && key.includes(scopes[i].toLowerCase())) {
                    // When performing a cache write, any token with a subset of requested scopes should be replaced
                    return true;
                }
            }
        }
        return true;
    };
    /**
     * Gets all access tokens matching the filter
     * @param filter
     * @returns
     */
    CacheManager.prototype.getAccessTokensByFilter = function (filter) {
        var _this = this;
        var tokenKeys = this.getTokenKeys();
        var accessTokens = [];
        tokenKeys.accessToken.forEach(function (key) {
            if (!_this.accessTokenKeyMatchesFilter(key, filter, true)) {
                return;
            }
            var accessToken = _this.getAccessTokenCredential(key);
            if (accessToken && _this.credentialMatchesFilter(accessToken, filter)) {
                accessTokens.push(accessToken);
            }
        });
        return accessTokens;
    };
    /**
     * Helper to retrieve the appropriate refresh token from cache
     * @param clientId
     * @param account
     * @param familyRT
     */
    CacheManager.prototype.getRefreshToken = function (account, familyRT, tokenKeys) {
        var _this = this;
        this.commonLogger.trace("CacheManager - getRefreshToken called");
        var id = familyRT ? THE_FAMILY_ID : undefined;
        var refreshTokenFilter = {
            homeAccountId: account.homeAccountId,
            environment: account.environment,
            credentialType: CredentialType.REFRESH_TOKEN,
            clientId: this.clientId,
            familyId: id,
        };
        var refreshTokenKeys = tokenKeys && tokenKeys.refreshToken || this.getTokenKeys().refreshToken;
        var refreshTokens = [];
        refreshTokenKeys.forEach(function (key) {
            // Validate key
            if (_this.refreshTokenKeyMatchesFilter(key, refreshTokenFilter)) {
                var refreshToken = _this.getRefreshTokenCredential(key);
                // Validate value
                if (refreshToken && _this.credentialMatchesFilter(refreshToken, refreshTokenFilter)) {
                    refreshTokens.push(refreshToken);
                }
            }
        });
        var numRefreshTokens = refreshTokens.length;
        if (numRefreshTokens < 1) {
            this.commonLogger.info("CacheManager:getRefreshToken - No refresh token found.");
            return null;
        }
        // address the else case after remove functions address environment aliases
        this.commonLogger.info("CacheManager:getRefreshToken - returning refresh token");
        return refreshTokens[0];
    };
    /**
     * Validate the cache key against filter before retrieving and parsing cache value
     * @param key
     * @param filter
     */
    CacheManager.prototype.refreshTokenKeyMatchesFilter = function (inputKey, filter) {
        var key = inputKey.toLowerCase();
        if (filter.familyId && key.indexOf(filter.familyId.toLowerCase()) === -1) {
            return false;
        }
        // If familyId is used, clientId is not in the key
        if (!filter.familyId && filter.clientId && key.indexOf(filter.clientId.toLowerCase()) === -1) {
            return false;
        }
        if (filter.homeAccountId && key.indexOf(filter.homeAccountId.toLowerCase()) === -1) {
            return false;
        }
        return true;
    };
    /**
     * Retrieve AppMetadataEntity from cache
     */
    CacheManager.prototype.readAppMetadataFromCache = function (environment) {
        var appMetadataFilter = {
            environment: environment,
            clientId: this.clientId,
        };
        var appMetadata = this.getAppMetadataFilteredBy(appMetadataFilter);
        var appMetadataEntries = Object.keys(appMetadata).map(function (key) { return appMetadata[key]; });
        var numAppMetadata = appMetadataEntries.length;
        if (numAppMetadata < 1) {
            return null;
        }
        else if (numAppMetadata > 1) {
            throw ClientAuthError.createMultipleMatchingAppMetadataInCacheError();
        }
        return appMetadataEntries[0];
    };
    /**
     * Return the family_id value associated  with FOCI
     * @param environment
     * @param clientId
     */
    CacheManager.prototype.isAppMetadataFOCI = function (environment) {
        var appMetadata = this.readAppMetadataFromCache(environment);
        return !!(appMetadata && appMetadata.familyId === THE_FAMILY_ID);
    };
    /**
     * helper to match account ids
     * @param value
     * @param homeAccountId
     */
    CacheManager.prototype.matchHomeAccountId = function (entity, homeAccountId) {
        return !!((typeof entity.homeAccountId === "string") && (homeAccountId === entity.homeAccountId));
    };
    /**
     * helper to match account ids
     * @param entity
     * @param localAccountId
     * @returns
     */
    CacheManager.prototype.matchLocalAccountId = function (entity, localAccountId) {
        return !!((typeof entity.localAccountId === "string") && (localAccountId === entity.localAccountId));
    };
    /**
     * helper to match usernames
     * @param entity
     * @param username
     * @returns
     */
    CacheManager.prototype.matchUsername = function (entity, username) {
        return !!((typeof entity.username === "string") && (username.toLowerCase() === entity.username.toLowerCase()));
    };
    /**
     * helper to match assertion
     * @param value
     * @param oboAssertion
     */
    CacheManager.prototype.matchUserAssertionHash = function (entity, userAssertionHash) {
        return !!(entity.userAssertionHash && userAssertionHash === entity.userAssertionHash);
    };
    /**
     * helper to match environment
     * @param value
     * @param environment
     */
    CacheManager.prototype.matchEnvironment = function (entity, environment) {
        var cloudMetadata = this.getAuthorityMetadataByAlias(environment);
        if (cloudMetadata && cloudMetadata.aliases.indexOf(entity.environment) > -1) {
            return true;
        }
        return false;
    };
    /**
     * helper to match credential type
     * @param entity
     * @param credentialType
     */
    CacheManager.prototype.matchCredentialType = function (entity, credentialType) {
        return (entity.credentialType && credentialType.toLowerCase() === entity.credentialType.toLowerCase());
    };
    /**
     * helper to match client ids
     * @param entity
     * @param clientId
     */
    CacheManager.prototype.matchClientId = function (entity, clientId) {
        return !!(entity.clientId && clientId === entity.clientId);
    };
    /**
     * helper to match family ids
     * @param entity
     * @param familyId
     */
    CacheManager.prototype.matchFamilyId = function (entity, familyId) {
        return !!(entity.familyId && familyId === entity.familyId);
    };
    /**
     * helper to match realm
     * @param entity
     * @param realm
     */
    CacheManager.prototype.matchRealm = function (entity, realm) {
        return !!(entity.realm && realm === entity.realm);
    };
    /**
     * helper to match nativeAccountId
     * @param entity
     * @param nativeAccountId
     * @returns boolean indicating the match result
     */
    CacheManager.prototype.matchNativeAccountId = function (entity, nativeAccountId) {
        return !!(entity.nativeAccountId && nativeAccountId === entity.nativeAccountId);
    };
    /**
     * Returns true if the target scopes are a subset of the current entity's scopes, false otherwise.
     * @param entity
     * @param target
     */
    CacheManager.prototype.matchTarget = function (entity, target) {
        var isNotAccessTokenCredential = (entity.credentialType !== CredentialType.ACCESS_TOKEN && entity.credentialType !== CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME);
        if (isNotAccessTokenCredential || !entity.target) {
            return false;
        }
        var entityScopeSet = ScopeSet.fromString(entity.target);
        return entityScopeSet.containsScopeSet(target);
    };
    /**
     * Returns true if the credential's tokenType or Authentication Scheme matches the one in the request, false otherwise
     * @param entity
     * @param tokenType
     */
    CacheManager.prototype.matchTokenType = function (entity, tokenType) {
        return !!(entity.tokenType && entity.tokenType === tokenType);
    };
    /**
     * Returns true if the credential's keyId matches the one in the request, false otherwise
     * @param entity
     * @param tokenType
     */
    CacheManager.prototype.matchKeyId = function (entity, keyId) {
        return !!(entity.keyId && entity.keyId === keyId);
    };
    /**
     * returns if a given cache entity is of the type appmetadata
     * @param key
     */
    CacheManager.prototype.isAppMetadata = function (key) {
        return key.indexOf(APP_METADATA) !== -1;
    };
    /**
     * returns if a given cache entity is of the type authoritymetadata
     * @param key
     */
    CacheManager.prototype.isAuthorityMetadata = function (key) {
        return key.indexOf(AUTHORITY_METADATA_CONSTANTS.CACHE_KEY) !== -1;
    };
    /**
     * returns cache key used for cloud instance metadata
     */
    CacheManager.prototype.generateAuthorityMetadataCacheKey = function (authority) {
        return AUTHORITY_METADATA_CONSTANTS.CACHE_KEY + "-" + this.clientId + "-" + authority;
    };
    /**
     * Helper to convert serialized data to object
     * @param obj
     * @param json
     */
    CacheManager.toObject = function (obj, json) {
        for (var propertyName in json) {
            obj[propertyName] = json[propertyName];
        }
        return obj;
    };
    return CacheManager;
}());
var DefaultStorageClass = /** @class */ (function (_super) {
    __extends(DefaultStorageClass, _super);
    function DefaultStorageClass() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    DefaultStorageClass.prototype.setAccount = function () {
        var notImplErr = "Storage interface - setAccount() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getAccount = function () {
        var notImplErr = "Storage interface - getAccount() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setIdTokenCredential = function () {
        var notImplErr = "Storage interface - setIdTokenCredential() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getIdTokenCredential = function () {
        var notImplErr = "Storage interface - getIdTokenCredential() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setAccessTokenCredential = function () {
        var notImplErr = "Storage interface - setAccessTokenCredential() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getAccessTokenCredential = function () {
        var notImplErr = "Storage interface - getAccessTokenCredential() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setRefreshTokenCredential = function () {
        var notImplErr = "Storage interface - setRefreshTokenCredential() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getRefreshTokenCredential = function () {
        var notImplErr = "Storage interface - getRefreshTokenCredential() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setAppMetadata = function () {
        var notImplErr = "Storage interface - setAppMetadata() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getAppMetadata = function () {
        var notImplErr = "Storage interface - getAppMetadata() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setServerTelemetry = function () {
        var notImplErr = "Storage interface - setServerTelemetry() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getServerTelemetry = function () {
        var notImplErr = "Storage interface - getServerTelemetry() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setAuthorityMetadata = function () {
        var notImplErr = "Storage interface - setAuthorityMetadata() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getAuthorityMetadata = function () {
        var notImplErr = "Storage interface - getAuthorityMetadata() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getAuthorityMetadataKeys = function () {
        var notImplErr = "Storage interface - getAuthorityMetadataKeys() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.setThrottlingCache = function () {
        var notImplErr = "Storage interface - setThrottlingCache() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getThrottlingCache = function () {
        var notImplErr = "Storage interface - getThrottlingCache() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.removeItem = function () {
        var notImplErr = "Storage interface - removeItem() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.containsKey = function () {
        var notImplErr = "Storage interface - containsKey() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getKeys = function () {
        var notImplErr = "Storage interface - getKeys() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getAccountKeys = function () {
        var notImplErr = "Storage interface - getAccountKeys() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.getTokenKeys = function () {
        var notImplErr = "Storage interface - getTokenKeys() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    DefaultStorageClass.prototype.clear = function () {
        return __awaiter(this, void 0, void 0, function () {
            var notImplErr;
            return __generator(this, function (_a) {
                notImplErr = "Storage interface - clear() has not been implemented for the cacheStorage interface.";
                throw AuthError.createUnexpectedError(notImplErr);
            });
        });
    };
    DefaultStorageClass.prototype.updateCredentialCacheKey = function () {
        var notImplErr = "Storage interface - updateCredentialCacheKey() has not been implemented for the cacheStorage interface.";
        throw AuthError.createUnexpectedError(notImplErr);
    };
    return DefaultStorageClass;
}(CacheManager));

export { CacheManager, DefaultStorageClass };
//# sourceMappingURL=CacheManager.js.map
