Skip to content

Commit e024778

Browse files
committed
hone surface for msal extension library
1 parent 73ebd27 commit e024778

File tree

8 files changed

+187
-94
lines changed

8 files changed

+187
-94
lines changed

lib/msal-node/src/cache/CacheContext.ts

-47
This file was deleted.
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { Storage } from './Storage';
2+
import { Serializer, Deserializer, InMemoryCache, JsonCache } from '@azure/msal-common';
3+
import { ICachePlugin } from './ICachePlugin';
4+
5+
const defaultSerializedCache: JsonCache = {
6+
Account: {},
7+
IdToken: {},
8+
AccessToken: {},
9+
RefreshToken: {},
10+
AppMetadata: {}
11+
};
12+
13+
14+
export class CacheManager {
15+
16+
hasChanged: boolean;
17+
storage: Storage;
18+
persistence: ICachePlugin;
19+
20+
constructor(storage: Storage, cachePlugin?: ICachePlugin) {
21+
this.hasChanged = false;
22+
this.storage = storage;
23+
this.storage.registerChangeEmitter(this.handleChangeEvent.bind(this))
24+
if (cachePlugin) {
25+
this.setPersistence(cachePlugin);
26+
}
27+
28+
}
29+
30+
setPersistence(persistence: ICachePlugin): void {
31+
this.persistence = persistence;
32+
}
33+
34+
handleChangeEvent() {
35+
this.hasChanged = true;
36+
}
37+
38+
mergeState(oldState: JsonCache, currentState: JsonCache) {
39+
// TODO
40+
// mergeUpdates(old, new)
41+
// mergeRemovals(old, new)
42+
return {
43+
...oldState,
44+
...currentState
45+
};
46+
}
47+
48+
//TODO think about separating serialize / deserialize from writeToPersistance and readFromPersistance
49+
50+
async serialize(): Promise<string> {
51+
const cache: string = JSON.stringify(Serializer.serializeAllCache(this.storage.getCache()));
52+
if (this.persistence) {
53+
await this.persistence.writeToStorage((stateFromDisk) => {
54+
const jsonFromDisk = JSON.parse(stateFromDisk);
55+
return JSON.stringify(
56+
this.mergeState(
57+
jsonFromDisk,
58+
Serializer.serializeAllCache(this.storage.getCache())
59+
), null, 4
60+
);
61+
});
62+
}
63+
this.hasChanged = false;
64+
return cache;
65+
}
66+
67+
async deserialize(cache?: string): Promise<void> {
68+
let deserializedCache: InMemoryCache;
69+
if (this.persistence) {
70+
const stringCacheFromStorage = await this.persistence.readFromStorage();
71+
deserializedCache = Deserializer.deserializeAllCache(this.overlayDefaults(JSON.parse(stringCacheFromStorage)));
72+
} else if (cache) {
73+
deserializedCache = Deserializer.deserializeAllCache(this.overlayDefaults(JSON.parse(cache)));
74+
} else {
75+
throw Error("Cache Must be passed in or configured");
76+
}
77+
this.storage.setCache(deserializedCache)
78+
}
79+
80+
cacheHasChanged(): boolean {
81+
return this.hasChanged;
82+
}
83+
84+
private overlayDefaults (passedInCache: JsonCache): JsonCache {
85+
return {
86+
Account: { ...defaultSerializedCache.Account, ...passedInCache.Account },
87+
IdToken: { ...defaultSerializedCache.IdToken, ...passedInCache.IdToken },
88+
AccessToken: { ...defaultSerializedCache.AccessToken, ...passedInCache.AccessToken },
89+
RefreshToken: { ...defaultSerializedCache.RefreshToken, ...passedInCache.RefreshToken },
90+
AppMetadata: { ...defaultSerializedCache.AppMetadata, ...passedInCache.AppMetadata}
91+
};
92+
}
93+
94+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
export interface ICachePlugin {
3+
readFromStorage: () => Promise<string>;
4+
writeToStorage: (getMergedState: (oldState: string) => string) => Promise<void>;
5+
}

lib/msal-node/src/cache/Storage.ts

+26-8
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,30 @@ import {
66
ICacheStorage,
77
InMemoryCache
88
} from '@azure/msal-common';
9-
import { CacheOptions } from '../config/Configuration';
109

1110
/**
1211
* This class implements Storage for node, reading cache from user specified storage location or an extension library
1312
*/
1413
export class Storage implements ICacheStorage {
1514
// Cache configuration, either set by user or default values.
16-
private cacheConfig: CacheOptions;;
17-
private inMemoryCache: InMemoryCache;
15+
private inMemoryCache: InMemoryCache = {
16+
accounts: {},
17+
accessTokens: {},
18+
refreshTokens: {},
19+
appMetadata: {},
20+
idTokens: {}
21+
};
22+
private changeEmitters: Array<Function> = [];
1823

19-
constructor(cacheConfig: CacheOptions) {
20-
this.cacheConfig = cacheConfig;
21-
if (this.cacheConfig.cacheLocation! === "fileCache")
22-
this.inMemoryCache = this.cacheConfig.cacheInMemory!;
24+
constructor() {
25+
}
26+
27+
registerChangeEmitter(func: () => void): void {
28+
this.changeEmitters.push(func);
29+
}
30+
31+
emitChange() {
32+
this.changeEmitters.forEach(func => func.call(null));
2333
}
2434

2535
/**
@@ -35,6 +45,7 @@ export class Storage implements ICacheStorage {
3545
*/
3646
setCache(inMemoryCache: InMemoryCache) {
3747
this.inMemoryCache = inMemoryCache;
48+
this.emitChange();
3849
}
3950

4051
/**
@@ -45,8 +56,10 @@ export class Storage implements ICacheStorage {
4556
*/
4657
setItem(key: string, value: string): void {
4758
if (key && value) {
59+
this.emitChange();
4860
return;
4961
}
62+
this.emitChange();
5063
}
5164

5265
/**
@@ -66,7 +79,11 @@ export class Storage implements ICacheStorage {
6679
* TODO: implement after the lookup implementation
6780
*/
6881
removeItem(key: string): void {
69-
if (!key) return;
82+
if (!key) {
83+
this.emitChange();
84+
return;
85+
}
86+
this.emitChange();
7087
}
7188

7289
/**
@@ -90,6 +107,7 @@ export class Storage implements ICacheStorage {
90107
* Clears all cache entries created by MSAL (except tokens).
91108
*/
92109
clear(): void {
110+
this.emitChange();
93111
return;
94112
}
95113
}

lib/msal-node/src/client/ClientApplication.ts

+6-11
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,19 @@ import {
1111
RefreshTokenClient,
1212
RefreshTokenRequest,
1313
AuthenticationResult,
14-
JsonCache,
15-
Serializer
1614
} from '@azure/msal-common';
1715
import { Configuration, buildAppConfiguration } from '../config/Configuration';
1816
import { CryptoProvider } from '../crypto/CryptoProvider';
1917
import { Storage } from '../cache/Storage';
2018
import { version } from '../../package.json';
2119
import { Constants } from './../utils/Constants';
22-
import { CacheContext } from '../cache/CacheContext';
20+
import { CacheManager } from '../cache/CacheManager';
2321

2422
export abstract class ClientApplication {
2523

2624
protected config: Configuration;
27-
protected cacheContext: CacheContext;
2825
protected storage: Storage;
26+
private cacheManager: CacheManager;
2927

3028
/**
3129
* @constructor
@@ -49,8 +47,8 @@ export abstract class ClientApplication {
4947
*/
5048
protected constructor(configuration: Configuration) {
5149
this.config = buildAppConfiguration(configuration);
52-
this.storage = new Storage(this.config.cache!);
53-
this.cacheContext = new CacheContext();
50+
this.storage = new Storage();
51+
this.cacheManager = new CacheManager(this.storage, this.config.cache?.cachePlugin);
5452
}
5553

5654
/**
@@ -126,11 +124,8 @@ export abstract class ClientApplication {
126124
};
127125
}
128126

129-
initializeCache(cacheObject: JsonCache) {
130-
this.cacheContext.setCurrentCache(this.storage, cacheObject)
127+
getCacheManager(): CacheManager {
128+
return this.cacheManager;
131129
}
132130

133-
readCache(): JsonCache {
134-
return Serializer.serializeAllCache(this.storage.getCache());
135-
}
136131
}

lib/msal-node/src/config/Configuration.ts

+5-14
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ import {
66
AuthOptions,
77
LoggerOptions,
88
INetworkModule,
9-
LogLevel,
10-
InMemoryCache,
9+
LogLevel
1110
} from '@azure/msal-common';
1211
import { NetworkUtils } from '../utils/NetworkUtils';
13-
import { CACHE } from '../utils/Constants';
1412
import debug from "debug";
13+
import { ICachePlugin } from 'cache/ICachePlugin';
1514

1615
export type NodeAuthOptions = AuthOptions;
1716

@@ -20,12 +19,12 @@ export type NodeAuthOptions = AuthOptions;
2019
*
2120
* - cacheLocation - Used to specify the cacheLocation user wants to set. Valid values are "localStorage" and "sessionStorage"
2221
* - storeAuthStateInCookie - If set, MSAL store's the auth request state required for validation of the auth flows in the browser cookies. By default this flag is set to false.
22+
* - cachePlugin for persistence provided to library
2323
*/
2424
// TODO Temporary placeholder - this will be rewritten by cache PR.
2525
export type CacheOptions = {
26-
cacheLocation?: string;
2726
storeAuthStateInCookie?: boolean;
28-
cacheInMemory?: InMemoryCache;
27+
cachePlugin?: ICachePlugin;
2928
};
3029

3130
/**
@@ -60,15 +59,7 @@ const DEFAULT_AUTH_OPTIONS: NodeAuthOptions = {
6059
};
6160

6261
const DEFAULT_CACHE_OPTIONS: CacheOptions = {
63-
cacheLocation: CACHE.FILE_CACHE,
64-
storeAuthStateInCookie: false,
65-
cacheInMemory: {
66-
accounts: {},
67-
idTokens: {},
68-
accessTokens: {},
69-
refreshTokens: {},
70-
appMetadata: {},
71-
},
62+
storeAuthStateInCookie: false
7263
};
7364

7465
const DEFAULT_LOGGER_OPTIONS: LoggerOptions = {

lib/msal-node/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export { Storage } from './cache/Storage';
55

66
// crypto
77
export { CryptoProvider } from './crypto/CryptoProvider';
8+
export { CacheManager } from './cache/CacheManager';
9+
export { ICachePlugin } from './cache/ICachePlugin';
810

911
// Common Object Formats
1012
export {

0 commit comments

Comments
 (0)