LookAtMySuitBot/js/node_modules/@azure/msal-node/dist/cache/TokenCache.mjs

275 lines
9.8 KiB
JavaScript
Raw Normal View History

2023-12-24 20:08:39 -05:00
/*! @azure/msal-node v2.5.1 2023-11-07 */
'use strict';
import { TokenCacheContext, AccountEntity } from '@azure/msal-common';
import { Deserializer } from './serializer/Deserializer.mjs';
import { Serializer } from './serializer/Serializer.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
const defaultSerializedCache = {
Account: {},
IdToken: {},
AccessToken: {},
RefreshToken: {},
AppMetadata: {},
};
/**
* In-memory token cache manager
* @public
*/
class TokenCache {
constructor(storage, logger, cachePlugin) {
this.cacheHasChanged = false;
this.storage = storage;
this.storage.registerChangeEmitter(this.handleChangeEvent.bind(this));
if (cachePlugin) {
this.persistence = cachePlugin;
}
this.logger = logger;
}
/**
* Set to true if cache state has changed since last time serialize or writeToPersistence was called
*/
hasChanged() {
return this.cacheHasChanged;
}
/**
* Serializes in memory cache to JSON
*/
serialize() {
this.logger.trace("Serializing in-memory cache");
let finalState = Serializer.serializeAllCache(this.storage.getInMemoryCache());
// if cacheSnapshot not null or empty, merge
if (this.cacheSnapshot) {
this.logger.trace("Reading cache snapshot from disk");
finalState = this.mergeState(JSON.parse(this.cacheSnapshot), finalState);
}
else {
this.logger.trace("No cache snapshot to merge");
}
this.cacheHasChanged = false;
return JSON.stringify(finalState);
}
/**
* Deserializes JSON to in-memory cache. JSON should be in MSAL cache schema format
* @param cache - blob formatted cache
*/
deserialize(cache) {
this.logger.trace("Deserializing JSON to in-memory cache");
this.cacheSnapshot = cache;
if (this.cacheSnapshot) {
this.logger.trace("Reading cache snapshot from disk");
const deserializedCache = Deserializer.deserializeAllCache(this.overlayDefaults(JSON.parse(this.cacheSnapshot)));
this.storage.setInMemoryCache(deserializedCache);
}
else {
this.logger.trace("No cache snapshot to deserialize");
}
}
/**
* Fetches the cache key-value map
*/
getKVStore() {
return this.storage.getCache();
}
/**
* API that retrieves all accounts currently in cache to the user
*/
async getAllAccounts() {
this.logger.trace("getAllAccounts called");
let cacheContext;
try {
if (this.persistence) {
cacheContext = new TokenCacheContext(this, false);
await this.persistence.beforeCacheAccess(cacheContext);
}
return this.storage.getAllAccounts();
}
finally {
if (this.persistence && cacheContext) {
await this.persistence.afterCacheAccess(cacheContext);
}
}
}
/**
* Returns the signed in account matching homeAccountId.
* (the account object is created at the time of successful login)
* or null when no matching account is found
* @param homeAccountId - unique identifier for an account (uid.utid)
*/
async getAccountByHomeId(homeAccountId) {
const allAccounts = await this.getAllAccounts();
if (homeAccountId && allAccounts && allAccounts.length) {
return (allAccounts.filter((accountObj) => accountObj.homeAccountId === homeAccountId)[0] || null);
}
else {
return null;
}
}
/**
* Returns the signed in account matching localAccountId.
* (the account object is created at the time of successful login)
* or null when no matching account is found
* @param localAccountId - unique identifier of an account (sub/obj when homeAccountId cannot be populated)
*/
async getAccountByLocalId(localAccountId) {
const allAccounts = await this.getAllAccounts();
if (localAccountId && allAccounts && allAccounts.length) {
return (allAccounts.filter((accountObj) => accountObj.localAccountId === localAccountId)[0] || null);
}
else {
return null;
}
}
/**
* API to remove a specific account and the relevant data from cache
* @param account - AccountInfo passed by the user
*/
async removeAccount(account) {
this.logger.trace("removeAccount called");
let cacheContext;
try {
if (this.persistence) {
cacheContext = new TokenCacheContext(this, true);
await this.persistence.beforeCacheAccess(cacheContext);
}
await this.storage.removeAccount(AccountEntity.generateAccountCacheKey(account));
}
finally {
if (this.persistence && cacheContext) {
await this.persistence.afterCacheAccess(cacheContext);
}
}
}
/**
* Called when the cache has changed state.
*/
handleChangeEvent() {
this.cacheHasChanged = true;
}
/**
* Merge in memory cache with the cache snapshot.
* @param oldState - cache before changes
* @param currentState - current cache state in the library
*/
mergeState(oldState, currentState) {
this.logger.trace("Merging in-memory cache with cache snapshot");
const stateAfterRemoval = this.mergeRemovals(oldState, currentState);
return this.mergeUpdates(stateAfterRemoval, currentState);
}
/**
* Deep update of oldState based on newState values
* @param oldState - cache before changes
* @param newState - updated cache
*/
mergeUpdates(oldState, newState) {
Object.keys(newState).forEach((newKey) => {
const newValue = newState[newKey];
// if oldState does not contain value but newValue does, add it
if (!oldState.hasOwnProperty(newKey)) {
if (newValue !== null) {
oldState[newKey] = newValue;
}
}
else {
// both oldState and newState contain the key, do deep update
const newValueNotNull = newValue !== null;
const newValueIsObject = typeof newValue === "object";
const newValueIsNotArray = !Array.isArray(newValue);
const oldStateNotUndefinedOrNull = typeof oldState[newKey] !== "undefined" &&
oldState[newKey] !== null;
if (newValueNotNull &&
newValueIsObject &&
newValueIsNotArray &&
oldStateNotUndefinedOrNull) {
this.mergeUpdates(oldState[newKey], newValue);
}
else {
oldState[newKey] = newValue;
}
}
});
return oldState;
}
/**
* Removes entities in oldState that the were removed from newState. If there are any unknown values in root of
* oldState that are not recognized, they are left untouched.
* @param oldState - cache before changes
* @param newState - updated cache
*/
mergeRemovals(oldState, newState) {
this.logger.trace("Remove updated entries in cache");
const accounts = oldState.Account
? this.mergeRemovalsDict(oldState.Account, newState.Account)
: oldState.Account;
const accessTokens = oldState.AccessToken
? this.mergeRemovalsDict(oldState.AccessToken, newState.AccessToken)
: oldState.AccessToken;
const refreshTokens = oldState.RefreshToken
? this.mergeRemovalsDict(oldState.RefreshToken, newState.RefreshToken)
: oldState.RefreshToken;
const idTokens = oldState.IdToken
? this.mergeRemovalsDict(oldState.IdToken, newState.IdToken)
: oldState.IdToken;
const appMetadata = oldState.AppMetadata
? this.mergeRemovalsDict(oldState.AppMetadata, newState.AppMetadata)
: oldState.AppMetadata;
return {
...oldState,
Account: accounts,
AccessToken: accessTokens,
RefreshToken: refreshTokens,
IdToken: idTokens,
AppMetadata: appMetadata,
};
}
/**
* Helper to merge new cache with the old one
* @param oldState - cache before changes
* @param newState - updated cache
*/
mergeRemovalsDict(oldState, newState) {
const finalState = { ...oldState };
Object.keys(oldState).forEach((oldKey) => {
if (!newState || !newState.hasOwnProperty(oldKey)) {
delete finalState[oldKey];
}
});
return finalState;
}
/**
* Helper to overlay as a part of cache merge
* @param passedInCache - cache read from the blob
*/
overlayDefaults(passedInCache) {
this.logger.trace("Overlaying input cache with the default cache");
return {
Account: {
...defaultSerializedCache.Account,
...passedInCache.Account,
},
IdToken: {
...defaultSerializedCache.IdToken,
...passedInCache.IdToken,
},
AccessToken: {
...defaultSerializedCache.AccessToken,
...passedInCache.AccessToken,
},
RefreshToken: {
...defaultSerializedCache.RefreshToken,
...passedInCache.RefreshToken,
},
AppMetadata: {
...defaultSerializedCache.AppMetadata,
...passedInCache.AppMetadata,
},
};
}
}
export { TokenCache };
//# sourceMappingURL=TokenCache.mjs.map