@azure/msal-node-extensions 1.0.0-alpha.8 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +208 -42
- package/bin/arm64/dpapi.node +0 -0
- package/bin/ia32/dpapi.node +0 -0
- package/bin/x64/dpapi.node +0 -0
- package/dist/{dpapi-addon/Dpapi.d.ts → Dpapi.d.ts} +4 -4
- package/dist/Dpapi.esm.js +24 -0
- package/dist/Dpapi.esm.js.map +1 -0
- package/dist/Dpapi.js +24 -0
- package/dist/Dpapi.js.map +1 -0
- package/dist/broker/NativeBrokerPlugin.d.ts +20 -0
- package/dist/broker/NativeBrokerPlugin.esm.js +408 -0
- package/dist/broker/NativeBrokerPlugin.esm.js.map +1 -0
- package/dist/broker/NativeBrokerPlugin.js +410 -0
- package/dist/broker/NativeBrokerPlugin.js.map +1 -0
- package/dist/error/NativeAuthError.d.ts +6 -0
- package/dist/error/NativeAuthError.esm.js +20 -0
- package/dist/error/NativeAuthError.esm.js.map +1 -0
- package/dist/error/NativeAuthError.js +22 -0
- package/dist/error/NativeAuthError.js.map +1 -0
- package/dist/error/PersistenceError.d.ts +21 -0
- package/{src/error/PersistenceError.ts → dist/error/PersistenceError.esm.js} +88 -70
- package/dist/error/PersistenceError.esm.js.map +1 -0
- package/dist/error/PersistenceError.js +91 -0
- package/dist/error/PersistenceError.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.esm.js +12 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +24 -6
- package/dist/index.js.map +1 -0
- package/dist/lock/CrossPlatformLock.esm.js +94 -0
- package/dist/lock/CrossPlatformLock.esm.js.map +1 -0
- package/dist/lock/CrossPlatformLock.js +96 -0
- package/dist/lock/CrossPlatformLock.js.map +1 -0
- package/dist/lock/CrossPlatformLockOptions.d.ts +1 -1
- package/dist/packageMetadata.d.ts +2 -0
- package/dist/packageMetadata.esm.js +8 -0
- package/dist/packageMetadata.esm.js.map +1 -0
- package/dist/packageMetadata.js +11 -0
- package/dist/packageMetadata.js.map +1 -0
- package/{src/persistence/BasePersistence.ts → dist/persistence/BasePersistence.esm.js} +35 -40
- package/dist/persistence/BasePersistence.esm.js.map +1 -0
- package/dist/persistence/BasePersistence.js +38 -0
- package/dist/persistence/BasePersistence.js.map +1 -0
- package/dist/persistence/DataProtectionScope.d.ts +5 -4
- package/{src/persistence/DataProtectionScope.ts → dist/persistence/DataProtectionScope.esm.js} +23 -19
- package/dist/persistence/DataProtectionScope.esm.js.map +1 -0
- package/dist/persistence/DataProtectionScope.js +26 -0
- package/dist/persistence/DataProtectionScope.js.map +1 -0
- package/dist/persistence/FilePersistence.d.ts +1 -0
- package/dist/persistence/FilePersistence.esm.js +173 -0
- package/dist/persistence/FilePersistence.esm.js.map +1 -0
- package/dist/persistence/FilePersistence.js +175 -0
- package/dist/persistence/FilePersistence.js.map +1 -0
- package/dist/persistence/FilePersistenceWithDataProtection.esm.js +84 -0
- package/dist/persistence/FilePersistenceWithDataProtection.esm.js.map +1 -0
- package/dist/persistence/FilePersistenceWithDataProtection.js +86 -0
- package/dist/persistence/FilePersistenceWithDataProtection.js.map +1 -0
- package/dist/persistence/IPersistenceConfiguration.d.ts +10 -0
- package/dist/persistence/KeychainPersistence.d.ts +2 -2
- package/dist/persistence/KeychainPersistence.esm.js +90 -0
- package/dist/persistence/KeychainPersistence.esm.js.map +1 -0
- package/dist/persistence/KeychainPersistence.js +92 -0
- package/dist/persistence/KeychainPersistence.js.map +1 -0
- package/dist/persistence/LibSecretPersistence.d.ts +2 -2
- package/dist/persistence/LibSecretPersistence.esm.js +91 -0
- package/dist/persistence/LibSecretPersistence.esm.js.map +1 -0
- package/dist/persistence/LibSecretPersistence.js +93 -0
- package/dist/persistence/LibSecretPersistence.js.map +1 -0
- package/dist/persistence/PersistenceCachePlugin.d.ts +1 -1
- package/{src/persistence/PersistenceCachePlugin.ts → dist/persistence/PersistenceCachePlugin.esm.js} +97 -104
- package/dist/persistence/PersistenceCachePlugin.esm.js.map +1 -0
- package/dist/persistence/PersistenceCachePlugin.js +101 -0
- package/dist/persistence/PersistenceCachePlugin.js.map +1 -0
- package/dist/persistence/PersistenceCreator.d.ts +5 -0
- package/dist/persistence/PersistenceCreator.esm.js +63 -0
- package/dist/persistence/PersistenceCreator.esm.js.map +1 -0
- package/dist/persistence/PersistenceCreator.js +65 -0
- package/dist/persistence/PersistenceCreator.js.map +1 -0
- package/dist/utils/Constants.d.ts +29 -0
- package/dist/utils/Constants.esm.js +62 -0
- package/dist/utils/Constants.esm.js.map +1 -0
- package/dist/utils/Constants.js +66 -0
- package/dist/utils/Constants.js.map +1 -0
- package/dist/utils/Environment.d.ts +16 -0
- package/dist/utils/Environment.esm.js +94 -0
- package/dist/utils/Environment.esm.js.map +1 -0
- package/dist/utils/Environment.js +96 -0
- package/dist/utils/Environment.js.map +1 -0
- package/dist/utils/TypeGuards.d.ts +5 -0
- package/dist/utils/TypeGuards.esm.js +16 -0
- package/dist/utils/TypeGuards.esm.js.map +1 -0
- package/dist/utils/TypeGuards.js +18 -0
- package/dist/utils/TypeGuards.js.map +1 -0
- package/package.json +70 -52
- package/CHANGELOG.json +0 -146
- package/binding.gyp +0 -29
- package/changelog.md +0 -68
- package/dist/msal-node-extensions.cjs.development.js +0 -687
- package/dist/msal-node-extensions.cjs.development.js.map +0 -1
- package/dist/msal-node-extensions.cjs.production.min.js +0 -2
- package/dist/msal-node-extensions.cjs.production.min.js.map +0 -1
- package/dist/msal-node-extensions.esm.js +0 -692
- package/dist/msal-node-extensions.esm.js.map +0 -1
- package/src/dpapi-addon/Dpapi.ts +0 -12
- package/src/dpapi-addon/dpapi_addon.h +0 -6
- package/src/dpapi-addon/dpapi_not_supported.cpp +0 -19
- package/src/dpapi-addon/dpapi_win.cpp +0 -114
- package/src/dpapi-addon/main.cpp +0 -32
- package/src/index.ts +0 -13
- package/src/lock/CrossPlatformLock.ts +0 -89
- package/src/lock/CrossPlatformLockOptions.ts +0 -15
- package/src/persistence/FilePersistence.ts +0 -140
- package/src/persistence/FilePersistenceWithDataProtection.ts +0 -92
- package/src/persistence/IPersistence.ts +0 -17
- package/src/persistence/KeychainPersistence.ts +0 -86
- package/src/persistence/LibSecretPersistence.ts +0 -87
- package/src/utils/Constants.ts +0 -35
|
@@ -1,687 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var fs = require('fs');
|
|
6
|
-
var process = require('process');
|
|
7
|
-
var path = require('path');
|
|
8
|
-
var msalCommon = require('@azure/msal-common');
|
|
9
|
-
var keytar = require('keytar');
|
|
10
|
-
|
|
11
|
-
/*
|
|
12
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
13
|
-
* Licensed under the MIT License.
|
|
14
|
-
*/
|
|
15
|
-
const Constants = {
|
|
16
|
-
/**
|
|
17
|
-
* An existing file was the target of an operation that required that the target not exist
|
|
18
|
-
*/
|
|
19
|
-
EEXIST_ERROR: "EEXIST",
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* No such file or directory: Commonly raised by fs operations to indicate that a component
|
|
23
|
-
* of the specified pathname does not exist. No entity (file or directory) could be found
|
|
24
|
-
* by the given path
|
|
25
|
-
*/
|
|
26
|
-
ENOENT_ERROR: "ENOENT",
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Operation not permitted. An attempt was made to perform an operation that requires
|
|
30
|
-
* elevated privileges.
|
|
31
|
-
*/
|
|
32
|
-
EPERM_ERROR: "EPERM",
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Default service name for using MSAL Keytar
|
|
36
|
-
*/
|
|
37
|
-
DEFAULT_SERVICE_NAME: "msal-node-extensions",
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Test data used to verify underlying persistence mechanism
|
|
41
|
-
*/
|
|
42
|
-
PERSISTENCE_TEST_DATA: "Dummy data to verify underlying persistence mechanism"
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/*
|
|
46
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
47
|
-
* Licensed under the MIT License.
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Error thrown when trying to write MSAL cache to persistence.
|
|
52
|
-
*/
|
|
53
|
-
class PersistenceError extends Error {
|
|
54
|
-
constructor(errorCode, errorMessage) {
|
|
55
|
-
const errorString = errorMessage ? `${errorCode}: ${errorMessage}` : errorCode;
|
|
56
|
-
super(errorString);
|
|
57
|
-
Object.setPrototypeOf(this, PersistenceError.prototype);
|
|
58
|
-
this.errorCode = errorCode;
|
|
59
|
-
this.errorMessage = errorMessage;
|
|
60
|
-
this.name = "PersistenceError";
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Error thrown when trying to access the file system.
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
static createFileSystemError(errorCode, errorMessage) {
|
|
68
|
-
return new PersistenceError(errorCode, errorMessage);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Error thrown when trying to write, load, or delete data from secret service on linux.
|
|
72
|
-
* Libsecret is used to access secret service.
|
|
73
|
-
*/
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
static createLibSecretError(errorMessage) {
|
|
77
|
-
return new PersistenceError("GnomeKeyringError", errorMessage);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Error thrown when trying to write, load, or delete data from keychain on macOs.
|
|
81
|
-
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
static createKeychainPersistenceError(errorMessage) {
|
|
85
|
-
return new PersistenceError("KeychainError", errorMessage);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Error thrown when trying to encrypt or decrypt data using DPAPI on Windows.
|
|
89
|
-
*/
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
static createFilePersistenceWithDPAPIError(errorMessage) {
|
|
93
|
-
return new PersistenceError("DPAPIEncryptedFileError", errorMessage);
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Error thrown when using the cross platform lock.
|
|
97
|
-
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
static createCrossPlatformLockError(errorMessage) {
|
|
101
|
-
return new PersistenceError("CrossPlatformLockError", errorMessage);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Throw cache persistence error
|
|
105
|
-
*
|
|
106
|
-
* @param errorMessage string
|
|
107
|
-
* @returns PersistenceError
|
|
108
|
-
*/
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
static createCachePersistenceError(errorMessage) {
|
|
112
|
-
return new PersistenceError("CachePersistenceError", errorMessage);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/*
|
|
118
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
119
|
-
* Licensed under the MIT License.
|
|
120
|
-
*/
|
|
121
|
-
/**
|
|
122
|
-
* Cross-process lock that works on all platforms.
|
|
123
|
-
*/
|
|
124
|
-
|
|
125
|
-
class CrossPlatformLock {
|
|
126
|
-
constructor(lockFilePath, logger, lockOptions) {
|
|
127
|
-
this.lockFilePath = lockFilePath;
|
|
128
|
-
this.retryNumber = lockOptions ? lockOptions.retryNumber : 500;
|
|
129
|
-
this.retryDelay = lockOptions ? lockOptions.retryDelay : 100;
|
|
130
|
-
this.logger = logger;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Locks cache from read or writes by creating file with same path and name as
|
|
134
|
-
* cache file but with .lockfile extension. If another process has already created
|
|
135
|
-
* the lockfile, will back off and retry based on configuration settings set by CrossPlatformLockOptions
|
|
136
|
-
*/
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
async lock() {
|
|
140
|
-
for (let tryCount = 0; tryCount < this.retryNumber; tryCount++) {
|
|
141
|
-
try {
|
|
142
|
-
this.logger.info(`Pid ${process.pid} trying to acquire lock`);
|
|
143
|
-
this.lockFileHandle = await fs.promises.open(this.lockFilePath, "wx+");
|
|
144
|
-
this.logger.info(`Pid ${process.pid} acquired lock`);
|
|
145
|
-
await this.lockFileHandle.write(process.pid.toString());
|
|
146
|
-
return;
|
|
147
|
-
} catch (err) {
|
|
148
|
-
if (err.code === Constants.EEXIST_ERROR || err.code === Constants.EPERM_ERROR) {
|
|
149
|
-
this.logger.info(err);
|
|
150
|
-
await this.sleep(this.retryDelay);
|
|
151
|
-
} else {
|
|
152
|
-
this.logger.error(`${process.pid} was not able to acquire lock. Ran into error: ${err.message}`);
|
|
153
|
-
throw PersistenceError.createCrossPlatformLockError(err.message);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
this.logger.error(`${process.pid} was not able to acquire lock. Exceeded amount of retries set in the options`);
|
|
159
|
-
throw PersistenceError.createCrossPlatformLockError("Not able to acquire lock. Exceeded amount of retries set in options");
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* unlocks cache file by deleting .lockfile.
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
async unlock() {
|
|
167
|
-
try {
|
|
168
|
-
if (this.lockFileHandle) {
|
|
169
|
-
// if we have a file handle to the .lockfile, delete lock file
|
|
170
|
-
await fs.promises.unlink(this.lockFilePath);
|
|
171
|
-
await this.lockFileHandle.close();
|
|
172
|
-
this.logger.info("lockfile deleted");
|
|
173
|
-
} else {
|
|
174
|
-
this.logger.warning("lockfile handle does not exist, so lockfile could not be deleted");
|
|
175
|
-
}
|
|
176
|
-
} catch (err) {
|
|
177
|
-
if (err.code === Constants.ENOENT_ERROR) {
|
|
178
|
-
this.logger.info("Tried to unlock but lockfile does not exist");
|
|
179
|
-
} else {
|
|
180
|
-
this.logger.error(`${process.pid} was not able to release lock. Ran into error: ${err.message}`);
|
|
181
|
-
throw PersistenceError.createCrossPlatformLockError(err.message);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
sleep(ms) {
|
|
187
|
-
return new Promise(resolve => {
|
|
188
|
-
setTimeout(resolve, ms);
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/*
|
|
195
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
196
|
-
* Licensed under the MIT License.
|
|
197
|
-
*/
|
|
198
|
-
/**
|
|
199
|
-
* MSAL cache plugin which enables callers to write the MSAL cache to disk on Windows,
|
|
200
|
-
* macOs, and Linux.
|
|
201
|
-
*
|
|
202
|
-
* - Persistence can be one of:
|
|
203
|
-
* - FilePersistence: Writes and reads from an unencrypted file. Can be used on Windows,
|
|
204
|
-
* macOs, or Linux.
|
|
205
|
-
* - FilePersistenceWithDataProtection: Used on Windows, writes and reads from file encrypted
|
|
206
|
-
* with windows dpapi-addon.
|
|
207
|
-
* - KeychainPersistence: Used on macOs, writes and reads from keychain.
|
|
208
|
-
* - LibSecretPersistence: Used on linux, writes and reads from secret service API. Requires
|
|
209
|
-
* libsecret be installed.
|
|
210
|
-
*/
|
|
211
|
-
|
|
212
|
-
class PersistenceCachePlugin {
|
|
213
|
-
constructor(persistence, lockOptions) {
|
|
214
|
-
this.persistence = persistence; // initialize logger
|
|
215
|
-
|
|
216
|
-
this.logger = persistence.getLogger(); // create file lock
|
|
217
|
-
|
|
218
|
-
this.lockFilePath = `${this.persistence.getFilePath()}.lockfile`;
|
|
219
|
-
this.crossPlatformLock = new CrossPlatformLock(this.lockFilePath, this.logger, lockOptions); // initialize default values
|
|
220
|
-
|
|
221
|
-
this.lastSync = 0;
|
|
222
|
-
this.currentCache = null;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Reads from storage and saves an in-memory copy. If persistence has not been updated
|
|
226
|
-
* since last time data was read, in memory copy is used.
|
|
227
|
-
*
|
|
228
|
-
* If cacheContext.cacheHasChanged === true, then file lock is created and not deleted until
|
|
229
|
-
* afterCacheAccess() is called, to prevent the cache file from changing in between
|
|
230
|
-
* beforeCacheAccess() and afterCacheAccess().
|
|
231
|
-
*/
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
async beforeCacheAccess(cacheContext) {
|
|
235
|
-
this.logger.info("Executing before cache access");
|
|
236
|
-
const reloadNecessary = await this.persistence.reloadNecessary(this.lastSync);
|
|
237
|
-
|
|
238
|
-
if (!reloadNecessary && this.currentCache !== null) {
|
|
239
|
-
if (cacheContext.cacheHasChanged) {
|
|
240
|
-
this.logger.verbose("Cache context has changed");
|
|
241
|
-
await this.crossPlatformLock.lock();
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
try {
|
|
248
|
-
this.logger.info(`Reload necessary. Last sync time: ${this.lastSync}`);
|
|
249
|
-
await this.crossPlatformLock.lock();
|
|
250
|
-
this.currentCache = await this.persistence.load();
|
|
251
|
-
this.lastSync = new Date().getTime();
|
|
252
|
-
cacheContext.tokenCache.deserialize(this.currentCache);
|
|
253
|
-
this.logger.info(`Last sync time updated to: ${this.lastSync}`);
|
|
254
|
-
} finally {
|
|
255
|
-
if (!cacheContext.cacheHasChanged) {
|
|
256
|
-
await this.crossPlatformLock.unlock();
|
|
257
|
-
this.logger.info(`Pid ${process.pid} released lock`);
|
|
258
|
-
} else {
|
|
259
|
-
this.logger.info(`Pid ${process.pid} beforeCacheAccess did not release lock`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Writes to storage if MSAL in memory copy of cache has been changed.
|
|
265
|
-
*/
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
async afterCacheAccess(cacheContext) {
|
|
269
|
-
this.logger.info("Executing after cache access");
|
|
270
|
-
|
|
271
|
-
try {
|
|
272
|
-
if (cacheContext.cacheHasChanged) {
|
|
273
|
-
this.logger.info("Msal in-memory cache has changed. Writing changes to persistence");
|
|
274
|
-
this.currentCache = cacheContext.tokenCache.serialize();
|
|
275
|
-
await this.persistence.save(this.currentCache);
|
|
276
|
-
} else {
|
|
277
|
-
this.logger.info("Msal in-memory cache has not changed. Did not write to persistence");
|
|
278
|
-
}
|
|
279
|
-
} finally {
|
|
280
|
-
await this.crossPlatformLock.unlock();
|
|
281
|
-
this.logger.info(`Pid ${process.pid} afterCacheAccess released lock`);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/*
|
|
288
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
289
|
-
* Licensed under the MIT License.
|
|
290
|
-
*/
|
|
291
|
-
class BasePersistence {
|
|
292
|
-
async verifyPersistence() {
|
|
293
|
-
// We are using a different location for the test to avoid overriding the functional cache
|
|
294
|
-
const persistenceValidator = await this.createForPersistenceValidation();
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
await persistenceValidator.save(Constants.PERSISTENCE_TEST_DATA);
|
|
298
|
-
const retrievedDummyData = await persistenceValidator.load();
|
|
299
|
-
|
|
300
|
-
if (!retrievedDummyData) {
|
|
301
|
-
throw PersistenceError.createCachePersistenceError("Persistence check failed. Data was written but it could not be read. " + "Possible cause: on Linux, LibSecret is installed but D-Bus isn't running because it cannot be started over SSH.");
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (retrievedDummyData !== Constants.PERSISTENCE_TEST_DATA) {
|
|
305
|
-
throw PersistenceError.createCachePersistenceError(`Persistence check failed. Data written ${Constants.PERSISTENCE_TEST_DATA} is different from data read ${retrievedDummyData}`);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
await persistenceValidator.delete();
|
|
309
|
-
return true;
|
|
310
|
-
} catch (e) {
|
|
311
|
-
throw PersistenceError.createCachePersistenceError(`Verifing persistence failed with the error: ${e}`);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/*
|
|
318
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
319
|
-
* Licensed under the MIT License.
|
|
320
|
-
*/
|
|
321
|
-
/**
|
|
322
|
-
* Reads and writes data to file specified by file location. File contents are not
|
|
323
|
-
* encrypted.
|
|
324
|
-
*
|
|
325
|
-
* If file or directory has not been created, it FilePersistence.create() will create
|
|
326
|
-
* file and any directories in the path recursively.
|
|
327
|
-
*/
|
|
328
|
-
|
|
329
|
-
class FilePersistence extends BasePersistence {
|
|
330
|
-
static async create(fileLocation, loggerOptions) {
|
|
331
|
-
const filePersistence = new FilePersistence();
|
|
332
|
-
filePersistence.filePath = fileLocation;
|
|
333
|
-
filePersistence.logger = new msalCommon.Logger(loggerOptions || FilePersistence.createDefaultLoggerOptions());
|
|
334
|
-
await filePersistence.createCacheFile();
|
|
335
|
-
return filePersistence;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async save(contents) {
|
|
339
|
-
try {
|
|
340
|
-
await fs.promises.writeFile(this.getFilePath(), contents, "utf-8");
|
|
341
|
-
} catch (err) {
|
|
342
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
async saveBuffer(contents) {
|
|
347
|
-
try {
|
|
348
|
-
await fs.promises.writeFile(this.getFilePath(), contents);
|
|
349
|
-
} catch (err) {
|
|
350
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
async load() {
|
|
355
|
-
try {
|
|
356
|
-
return await fs.promises.readFile(this.getFilePath(), "utf-8");
|
|
357
|
-
} catch (err) {
|
|
358
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
async loadBuffer() {
|
|
363
|
-
try {
|
|
364
|
-
return await fs.promises.readFile(this.getFilePath());
|
|
365
|
-
} catch (err) {
|
|
366
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
async delete() {
|
|
371
|
-
try {
|
|
372
|
-
await fs.promises.unlink(this.getFilePath());
|
|
373
|
-
return true;
|
|
374
|
-
} catch (err) {
|
|
375
|
-
if (err.code === Constants.ENOENT_ERROR) {
|
|
376
|
-
// file does not exist, so it was not deleted
|
|
377
|
-
this.logger.warning("Cache file does not exist, so it could not be deleted");
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
getFilePath() {
|
|
386
|
-
return this.filePath;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
async reloadNecessary(lastSync) {
|
|
390
|
-
return lastSync < (await this.timeLastModified());
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
getLogger() {
|
|
394
|
-
return this.logger;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
createForPersistenceValidation() {
|
|
398
|
-
const testCacheFileLocation = `${path.dirname(this.filePath)}/test.cache`;
|
|
399
|
-
return FilePersistence.create(testCacheFileLocation);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
static createDefaultLoggerOptions() {
|
|
403
|
-
return {
|
|
404
|
-
loggerCallback: () => {// allow users to not set loggerCallback
|
|
405
|
-
},
|
|
406
|
-
piiLoggingEnabled: false,
|
|
407
|
-
logLevel: msalCommon.LogLevel.Info
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
async timeLastModified() {
|
|
412
|
-
try {
|
|
413
|
-
const stats = await fs.promises.stat(this.filePath);
|
|
414
|
-
return stats.mtime.getTime();
|
|
415
|
-
} catch (err) {
|
|
416
|
-
if (err.code === Constants.ENOENT_ERROR) {
|
|
417
|
-
// file does not exist, so it's never been modified
|
|
418
|
-
this.logger.verbose("Cache file does not exist");
|
|
419
|
-
return 0;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
async createCacheFile() {
|
|
427
|
-
await this.createFileDirectory(); // File is created only if it does not exist
|
|
428
|
-
|
|
429
|
-
const fileHandle = await fs.promises.open(this.filePath, "a");
|
|
430
|
-
await fileHandle.close();
|
|
431
|
-
this.logger.info(`File created at ${this.filePath}`);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
async createFileDirectory() {
|
|
435
|
-
try {
|
|
436
|
-
await fs.promises.mkdir(path.dirname(this.filePath), {
|
|
437
|
-
recursive: true
|
|
438
|
-
});
|
|
439
|
-
} catch (err) {
|
|
440
|
-
if (err.code === Constants.EEXIST_ERROR) {
|
|
441
|
-
this.logger.info(`Directory ${path.dirname(this.filePath)} already exists`);
|
|
442
|
-
} else {
|
|
443
|
-
throw PersistenceError.createFileSystemError(err.code, err.message);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/*
|
|
451
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
452
|
-
* Licensed under the MIT License.
|
|
453
|
-
*/
|
|
454
|
-
|
|
455
|
-
/* eslint-disable-next-line @typescript-eslint/no-var-requires, no-var */
|
|
456
|
-
var Dpapi = /*#__PURE__*/require("bindings")("dpapi");
|
|
457
|
-
|
|
458
|
-
/*
|
|
459
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
460
|
-
* Licensed under the MIT License.
|
|
461
|
-
*/
|
|
462
|
-
|
|
463
|
-
(function (DataProtectionScope) {
|
|
464
|
-
DataProtectionScope["CurrentUser"] = "CurrentUser";
|
|
465
|
-
DataProtectionScope["LocalMachine"] = "LocalMachine";
|
|
466
|
-
})(exports.DataProtectionScope || (exports.DataProtectionScope = {}));
|
|
467
|
-
|
|
468
|
-
/*
|
|
469
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
470
|
-
* Licensed under the MIT License.
|
|
471
|
-
*/
|
|
472
|
-
/**
|
|
473
|
-
* Uses CryptProtectData and CryptUnprotectData on Windows to encrypt and decrypt file contents.
|
|
474
|
-
*
|
|
475
|
-
* scope: Scope of the data protection. Either local user or the current machine
|
|
476
|
-
* optionalEntropy: Password or other additional entropy used to encrypt the data
|
|
477
|
-
*/
|
|
478
|
-
|
|
479
|
-
class FilePersistenceWithDataProtection extends BasePersistence {
|
|
480
|
-
constructor(scope, optionalEntropy) {
|
|
481
|
-
super();
|
|
482
|
-
this.scope = scope;
|
|
483
|
-
this.optionalEntropy = optionalEntropy ? Buffer.from(optionalEntropy, "utf-8") : null;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
static async create(fileLocation, scope, optionalEntropy, loggerOptions) {
|
|
487
|
-
const persistence = new FilePersistenceWithDataProtection(scope, optionalEntropy);
|
|
488
|
-
persistence.filePersistence = await FilePersistence.create(fileLocation, loggerOptions);
|
|
489
|
-
return persistence;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
async save(contents) {
|
|
493
|
-
try {
|
|
494
|
-
const encryptedContents = Dpapi.protectData(Buffer.from(contents, "utf-8"), this.optionalEntropy, this.scope.toString());
|
|
495
|
-
await this.filePersistence.saveBuffer(encryptedContents);
|
|
496
|
-
} catch (err) {
|
|
497
|
-
throw PersistenceError.createFilePersistenceWithDPAPIError(err.message);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
async load() {
|
|
502
|
-
try {
|
|
503
|
-
const encryptedContents = await this.filePersistence.loadBuffer();
|
|
504
|
-
|
|
505
|
-
if (typeof encryptedContents === "undefined" || !encryptedContents || 0 === encryptedContents.length) {
|
|
506
|
-
this.filePersistence.getLogger().info("Encrypted contents loaded from file were null or empty");
|
|
507
|
-
return null;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
return Dpapi.unprotectData(encryptedContents, this.optionalEntropy, this.scope.toString()).toString();
|
|
511
|
-
} catch (err) {
|
|
512
|
-
throw PersistenceError.createFilePersistenceWithDPAPIError(err.message);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
async delete() {
|
|
517
|
-
return this.filePersistence.delete();
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
async reloadNecessary(lastSync) {
|
|
521
|
-
return this.filePersistence.reloadNecessary(lastSync);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
getFilePath() {
|
|
525
|
-
return this.filePersistence.getFilePath();
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
getLogger() {
|
|
529
|
-
return this.filePersistence.getLogger();
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
createForPersistenceValidation() {
|
|
533
|
-
const testCacheFileLocation = `${path.dirname(this.filePersistence.getFilePath())}/test.cache`;
|
|
534
|
-
return FilePersistenceWithDataProtection.create(testCacheFileLocation, exports.DataProtectionScope.CurrentUser);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/*
|
|
540
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
541
|
-
* Licensed under the MIT License.
|
|
542
|
-
*/
|
|
543
|
-
/**
|
|
544
|
-
* Uses reads and writes passwords to macOS keychain
|
|
545
|
-
*
|
|
546
|
-
* serviceName: Identifier used as key for whatever value is stored
|
|
547
|
-
* accountName: Account under which password should be stored
|
|
548
|
-
*/
|
|
549
|
-
|
|
550
|
-
class KeychainPersistence extends BasePersistence {
|
|
551
|
-
constructor(serviceName, accountName) {
|
|
552
|
-
super();
|
|
553
|
-
this.serviceName = serviceName;
|
|
554
|
-
this.accountName = accountName;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
static async create(fileLocation, serviceName, accountName, loggerOptions) {
|
|
558
|
-
const persistence = new KeychainPersistence(serviceName, accountName);
|
|
559
|
-
persistence.filePersistence = await FilePersistence.create(fileLocation, loggerOptions);
|
|
560
|
-
return persistence;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
async save(contents) {
|
|
564
|
-
try {
|
|
565
|
-
await keytar.setPassword(this.serviceName, this.accountName, contents);
|
|
566
|
-
} catch (err) {
|
|
567
|
-
throw PersistenceError.createKeychainPersistenceError(err.message);
|
|
568
|
-
} // Write dummy data to update file mtime
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
await this.filePersistence.save("{}");
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
async load() {
|
|
575
|
-
try {
|
|
576
|
-
return await keytar.getPassword(this.serviceName, this.accountName);
|
|
577
|
-
} catch (err) {
|
|
578
|
-
throw PersistenceError.createKeychainPersistenceError(err.message);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
async delete() {
|
|
583
|
-
try {
|
|
584
|
-
await this.filePersistence.delete();
|
|
585
|
-
return await keytar.deletePassword(this.serviceName, this.accountName);
|
|
586
|
-
} catch (err) {
|
|
587
|
-
throw PersistenceError.createKeychainPersistenceError(err.message);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
async reloadNecessary(lastSync) {
|
|
592
|
-
return this.filePersistence.reloadNecessary(lastSync);
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
getFilePath() {
|
|
596
|
-
return this.filePersistence.getFilePath();
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
getLogger() {
|
|
600
|
-
return this.filePersistence.getLogger();
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
createForPersistenceValidation() {
|
|
604
|
-
const testCacheFileLocation = `${path.dirname(this.filePersistence.getFilePath())}/test.cache`;
|
|
605
|
-
return KeychainPersistence.create(testCacheFileLocation, "persistenceValidationServiceName", "persistencValidationAccountName");
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/*
|
|
611
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
612
|
-
* Licensed under the MIT License.
|
|
613
|
-
*/
|
|
614
|
-
/**
|
|
615
|
-
* Uses reads and writes passwords to Secret Service API/libsecret. Requires libsecret
|
|
616
|
-
* to be installed.
|
|
617
|
-
*
|
|
618
|
-
* serviceName: Identifier used as key for whatever value is stored
|
|
619
|
-
* accountName: Account under which password should be stored
|
|
620
|
-
*/
|
|
621
|
-
|
|
622
|
-
class LibSecretPersistence extends BasePersistence {
|
|
623
|
-
constructor(serviceName, accountName) {
|
|
624
|
-
super();
|
|
625
|
-
this.serviceName = serviceName;
|
|
626
|
-
this.accountName = accountName;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
static async create(fileLocation, serviceName, accountName, loggerOptions) {
|
|
630
|
-
const persistence = new LibSecretPersistence(serviceName, accountName);
|
|
631
|
-
persistence.filePersistence = await FilePersistence.create(fileLocation, loggerOptions);
|
|
632
|
-
return persistence;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
async save(contents) {
|
|
636
|
-
try {
|
|
637
|
-
await keytar.setPassword(this.serviceName, this.accountName, contents);
|
|
638
|
-
} catch (err) {
|
|
639
|
-
throw PersistenceError.createLibSecretError(err.message);
|
|
640
|
-
} // Write dummy data to update file mtime
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
await this.filePersistence.save("{}");
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
async load() {
|
|
647
|
-
try {
|
|
648
|
-
return await keytar.getPassword(this.serviceName, this.accountName);
|
|
649
|
-
} catch (err) {
|
|
650
|
-
throw PersistenceError.createLibSecretError(err.message);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
async delete() {
|
|
655
|
-
try {
|
|
656
|
-
await this.filePersistence.delete();
|
|
657
|
-
return await keytar.deletePassword(this.serviceName, this.accountName);
|
|
658
|
-
} catch (err) {
|
|
659
|
-
throw PersistenceError.createLibSecretError(err.message);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
async reloadNecessary(lastSync) {
|
|
664
|
-
return this.filePersistence.reloadNecessary(lastSync);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
getFilePath() {
|
|
668
|
-
return this.filePersistence.getFilePath();
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
getLogger() {
|
|
672
|
-
return this.filePersistence.getLogger();
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
createForPersistenceValidation() {
|
|
676
|
-
const testCacheFileLocation = `${path.dirname(this.filePersistence.getFilePath())}/test.cache`;
|
|
677
|
-
return LibSecretPersistence.create(testCacheFileLocation, "persistenceValidationServiceName", "persistencValidationAccountName");
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
exports.FilePersistence = FilePersistence;
|
|
683
|
-
exports.FilePersistenceWithDataProtection = FilePersistenceWithDataProtection;
|
|
684
|
-
exports.KeychainPersistence = KeychainPersistence;
|
|
685
|
-
exports.LibSecretPersistence = LibSecretPersistence;
|
|
686
|
-
exports.PersistenceCachePlugin = PersistenceCachePlugin;
|
|
687
|
-
//# sourceMappingURL=msal-node-extensions.cjs.development.js.map
|