@salesforce/core 3.30.10 → 3.30.11
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/README.md +3 -3
- package/lib/config/aliasesConfig.js +1 -0
- package/lib/config/config.js +6 -9
- package/lib/config/configAggregator.d.ts +3 -3
- package/lib/config/configAggregator.js +14 -14
- package/lib/config/configFile.js +7 -9
- package/lib/config/configGroup.js +8 -7
- package/lib/config/configStore.d.ts +4 -4
- package/lib/config/configStore.js +12 -9
- package/lib/config/envVars.js +1 -1
- package/lib/config/tokensConfig.js +1 -0
- package/lib/config/ttlConfig.d.ts +2 -0
- package/lib/config/ttlConfig.js +5 -4
- package/lib/crypto/crypto.js +9 -12
- package/lib/crypto/keyChainImpl.d.ts +2 -0
- package/lib/crypto/keyChainImpl.js +41 -34
- package/lib/deviceOauthService.js +5 -2
- package/lib/exported.js +5 -1
- package/lib/global.js +2 -0
- package/lib/lifecycleEvents.js +3 -0
- package/lib/logger.d.ts +2 -3
- package/lib/logger.js +57 -53
- package/lib/messages.js +2 -3
- package/lib/org/authInfo.js +40 -29
- package/lib/org/authRemover.js +11 -7
- package/lib/org/connection.d.ts +4 -4
- package/lib/org/connection.js +8 -6
- package/lib/org/index.js +5 -1
- package/lib/org/org.js +23 -15
- package/lib/org/scratchOrgCreate.js +2 -1
- package/lib/org/scratchOrgInfoApi.js +4 -6
- package/lib/org/scratchOrgInfoGenerator.d.ts +1 -0
- package/lib/org/scratchOrgInfoGenerator.js +28 -27
- package/lib/org/scratchOrgLifecycleEvents.js +2 -6
- package/lib/org/scratchOrgSettingsGenerator.js +9 -9
- package/lib/org/scratchOrgTypes.d.ts +1 -1
- package/lib/org/user.js +7 -6
- package/lib/schema/printer.d.ts +4 -0
- package/lib/schema/printer.js +30 -29
- package/lib/schema/validator.d.ts +1 -1
- package/lib/schema/validator.js +2 -1
- package/lib/sfError.d.ts +3 -6
- package/lib/sfError.js +26 -9
- package/lib/sfProject.js +14 -6
- package/lib/stateAggregator/accessors/aliasAccessor.js +2 -1
- package/lib/stateAggregator/accessors/orgAccessor.js +11 -6
- package/lib/stateAggregator/accessors/sandboxAccessor.js +1 -0
- package/lib/stateAggregator/index.js +5 -1
- package/lib/status/myDomainResolver.d.ts +1 -1
- package/lib/status/myDomainResolver.js +4 -4
- package/lib/status/streamingClient.js +51 -49
- package/lib/testSetup.d.ts +5 -1
- package/lib/testSetup.js +32 -21
- package/lib/util/cache.d.ts +2 -2
- package/lib/util/cache.js +6 -6
- package/lib/util/directoryWriter.d.ts +2 -1
- package/lib/util/directoryWriter.js +5 -3
- package/lib/util/jsonXmlTools.js +2 -4
- package/lib/util/mapKeys.d.ts +9 -9
- package/lib/util/mapKeys.js +13 -9
- package/lib/util/sfdc.d.ts +2 -2
- package/lib/util/sfdc.js +8 -17
- package/lib/util/sfdcUrl.d.ts +1 -1
- package/lib/util/sfdcUrl.js +2 -4
- package/lib/util/structuredWriter.d.ts +1 -0
- package/lib/util/zipWriter.d.ts +2 -1
- package/lib/util/zipWriter.js +5 -9
- package/lib/webOAuthServer.js +9 -3
- package/package.json +16 -17
|
@@ -37,9 +37,7 @@ const GET_PASSWORD_RETRY_COUNT = 3;
|
|
|
37
37
|
*
|
|
38
38
|
* @param optionsArray CLI command args.
|
|
39
39
|
*/
|
|
40
|
-
|
|
41
|
-
return optionsArray.reduce((accum, element) => `${accum} ${element}`);
|
|
42
|
-
}
|
|
40
|
+
const optionsToString = (optionsArray) => optionsArray.join(' ');
|
|
43
41
|
/**
|
|
44
42
|
* Helper to determine if a program is executable. Returns `true` if the program is executable for the user. For
|
|
45
43
|
* Windows true is always returned.
|
|
@@ -48,7 +46,7 @@ function _optionsToString(optionsArray) {
|
|
|
48
46
|
* @param gid Unix group id.
|
|
49
47
|
* @param uid Unix user id.
|
|
50
48
|
*/
|
|
51
|
-
const
|
|
49
|
+
const isExe = (mode, gid, uid) => {
|
|
52
50
|
if (process.platform === 'win32') {
|
|
53
51
|
return true;
|
|
54
52
|
}
|
|
@@ -67,7 +65,10 @@ const _isExe = (mode, gid, uid) => {
|
|
|
67
65
|
* @param fsIfc The file system interface.
|
|
68
66
|
* @param isExeIfc Executable validation function.
|
|
69
67
|
*/
|
|
70
|
-
|
|
68
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
69
|
+
const _validateProgram = async (programPath, fsIfc, isExeIfc
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
71
|
+
) => {
|
|
71
72
|
let noPermission;
|
|
72
73
|
try {
|
|
73
74
|
const stats = fsIfc.statSync(programPath);
|
|
@@ -98,7 +99,7 @@ class KeychainAccess {
|
|
|
98
99
|
* Validates the os level program is executable.
|
|
99
100
|
*/
|
|
100
101
|
async validateProgram() {
|
|
101
|
-
await _validateProgram(this.osImpl.getProgram(), this.fsIfc,
|
|
102
|
+
await _validateProgram(this.osImpl.getProgram(), this.fsIfc, isExe);
|
|
102
103
|
}
|
|
103
104
|
/**
|
|
104
105
|
* Returns a password using the native program for credential management.
|
|
@@ -136,6 +137,7 @@ class KeychainAccess {
|
|
|
136
137
|
return await this.osImpl.onGetCommandClose(code, stdout, stderr, opts, fn);
|
|
137
138
|
}
|
|
138
139
|
catch (e) {
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
139
141
|
// @ts-ignore
|
|
140
142
|
if (e.retry) {
|
|
141
143
|
if (retryCount >= GET_PASSWORD_RETRY_COUNT) {
|
|
@@ -172,7 +174,7 @@ class KeychainAccess {
|
|
|
172
174
|
fn(messages.createError('passwordRequiredError'));
|
|
173
175
|
return;
|
|
174
176
|
}
|
|
175
|
-
await _validateProgram(this.osImpl.getProgram(), this.fsIfc,
|
|
177
|
+
await _validateProgram(this.osImpl.getProgram(), this.fsIfc, isExe);
|
|
176
178
|
const credManager = this.osImpl.setCommandFunc(opts, childProcess.spawn);
|
|
177
179
|
let stdout = '';
|
|
178
180
|
let stderr = '';
|
|
@@ -188,7 +190,7 @@ class KeychainAccess {
|
|
|
188
190
|
}
|
|
189
191
|
credManager.on('close',
|
|
190
192
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
191
|
-
async (code) =>
|
|
193
|
+
async (code) => this.osImpl.onSetCommandClose(code, stdout, stderr, opts, fn));
|
|
192
194
|
if (credManager.stdin) {
|
|
193
195
|
credManager.stdin.end();
|
|
194
196
|
}
|
|
@@ -200,23 +202,25 @@ exports.KeychainAccess = KeychainAccess;
|
|
|
200
202
|
*
|
|
201
203
|
* Uses libsecret.
|
|
202
204
|
*/
|
|
203
|
-
const
|
|
205
|
+
const linuxImpl = {
|
|
204
206
|
getProgram() {
|
|
205
|
-
return process.env.SFDX_SECRET_TOOL_PATH
|
|
207
|
+
return process.env.SFDX_SECRET_TOOL_PATH ?? path.join(path.sep, 'usr', 'bin', 'secret-tool');
|
|
206
208
|
},
|
|
207
209
|
getProgramOptions(opts) {
|
|
208
210
|
return ['lookup', 'user', opts.account, 'domain', opts.service];
|
|
209
211
|
},
|
|
210
212
|
getCommandFunc(opts, fn) {
|
|
211
|
-
return fn(
|
|
213
|
+
return fn(linuxImpl.getProgram(), linuxImpl.getProgramOptions(opts));
|
|
212
214
|
},
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
213
216
|
async onGetCommandClose(code, stdout, stderr, opts, fn) {
|
|
214
217
|
if (code === 1) {
|
|
215
|
-
const command = `${
|
|
218
|
+
const command = `${linuxImpl.getProgram()} ${optionsToString(linuxImpl.getProgramOptions(opts))}`;
|
|
216
219
|
const error = messages.createError('passwordNotFoundError', [], [command]);
|
|
217
220
|
// This is a workaround for linux.
|
|
218
221
|
// Calling secret-tool too fast can cause it to return an unexpected error. (below)
|
|
219
|
-
if (stderr
|
|
222
|
+
if (stderr?.includes('invalid or unencryptable secret')) {
|
|
223
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
220
224
|
// @ts-ignore TODO: make an error subclass with this field
|
|
221
225
|
error.retry = true;
|
|
222
226
|
// Throwing here allows us to perform a retry in KeychainAccess
|
|
@@ -233,15 +237,16 @@ const _linuxImpl = {
|
|
|
233
237
|
return ['store', "--label='salesforce.com'", 'user', opts.account, 'domain', opts.service];
|
|
234
238
|
},
|
|
235
239
|
setCommandFunc(opts, fn) {
|
|
236
|
-
const secretTool = fn(
|
|
240
|
+
const secretTool = fn(linuxImpl.getProgram(), linuxImpl.setProgramOptions(opts));
|
|
237
241
|
if (secretTool.stdin) {
|
|
238
242
|
secretTool.stdin.write(`${opts.password}\n`);
|
|
239
243
|
}
|
|
240
244
|
return secretTool;
|
|
241
245
|
},
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
242
247
|
async onSetCommandClose(code, stdout, stderr, opts, fn) {
|
|
243
248
|
if (code !== 0) {
|
|
244
|
-
const command = `${
|
|
249
|
+
const command = `${linuxImpl.getProgram()} ${optionsToString(linuxImpl.setProgramOptions(opts))}`;
|
|
245
250
|
fn(messages.createError('setCredentialError', [`${stdout} - ${stderr}`], [os.userInfo().username, command]));
|
|
246
251
|
}
|
|
247
252
|
else {
|
|
@@ -254,7 +259,7 @@ const _linuxImpl = {
|
|
|
254
259
|
*
|
|
255
260
|
* /usr/bin/security is a cli front end for OSX keychain.
|
|
256
261
|
*/
|
|
257
|
-
const
|
|
262
|
+
const darwinImpl = {
|
|
258
263
|
getProgram() {
|
|
259
264
|
return path.join(path.sep, 'usr', 'bin', 'security');
|
|
260
265
|
},
|
|
@@ -262,8 +267,9 @@ const _darwinImpl = {
|
|
|
262
267
|
return ['find-generic-password', '-a', opts.account, '-s', opts.service, '-g'];
|
|
263
268
|
},
|
|
264
269
|
getCommandFunc(opts, fn) {
|
|
265
|
-
return fn(
|
|
270
|
+
return fn(darwinImpl.getProgram(), darwinImpl.getProgramOptions(opts));
|
|
266
271
|
},
|
|
272
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
267
273
|
async onGetCommandClose(code, stdout, stderr, opts, fn) {
|
|
268
274
|
let err;
|
|
269
275
|
if (code !== 0) {
|
|
@@ -273,7 +279,7 @@ const _darwinImpl = {
|
|
|
273
279
|
break;
|
|
274
280
|
}
|
|
275
281
|
default: {
|
|
276
|
-
const command = `${
|
|
282
|
+
const command = `${darwinImpl.getProgram()} ${optionsToString(darwinImpl.getProgramOptions(opts))}`;
|
|
277
283
|
err = messages.createError('passwordNotFoundError', [`${stdout} - ${stderr}`], [command]);
|
|
278
284
|
}
|
|
279
285
|
}
|
|
@@ -292,7 +298,7 @@ const _darwinImpl = {
|
|
|
292
298
|
}
|
|
293
299
|
}
|
|
294
300
|
else {
|
|
295
|
-
const command = `${
|
|
301
|
+
const command = `${darwinImpl.getProgram()} ${optionsToString(darwinImpl.getProgramOptions(opts))}`;
|
|
296
302
|
fn(messages.createError('passwordNotFoundError', [`${stdout} - ${stderr}`], [command]));
|
|
297
303
|
}
|
|
298
304
|
},
|
|
@@ -304,11 +310,12 @@ const _darwinImpl = {
|
|
|
304
310
|
return result;
|
|
305
311
|
},
|
|
306
312
|
setCommandFunc(opts, fn) {
|
|
307
|
-
return fn(
|
|
313
|
+
return fn(darwinImpl.getProgram(), darwinImpl.setProgramOptions(opts));
|
|
308
314
|
},
|
|
315
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
309
316
|
async onSetCommandClose(code, stdout, stderr, opts, fn) {
|
|
310
317
|
if (code !== 0) {
|
|
311
|
-
const command = `${
|
|
318
|
+
const command = `${darwinImpl.getProgram()} ${optionsToString(darwinImpl.setProgramOptions(opts))}`;
|
|
312
319
|
fn(messages.createError('setCredentialError', [`${stdout} - ${stderr}`], [os.userInfo().username, command]));
|
|
313
320
|
}
|
|
314
321
|
else {
|
|
@@ -323,7 +330,7 @@ var SecretField;
|
|
|
323
330
|
SecretField["ACCOUNT"] = "account";
|
|
324
331
|
SecretField["KEY"] = "key";
|
|
325
332
|
})(SecretField || (SecretField = {}));
|
|
326
|
-
async function
|
|
333
|
+
async function writeFile(opts, fn) {
|
|
327
334
|
try {
|
|
328
335
|
const contents = {
|
|
329
336
|
[SecretField.ACCOUNT]: opts.account,
|
|
@@ -339,7 +346,7 @@ async function _writeFile(opts, fn) {
|
|
|
339
346
|
fn(err);
|
|
340
347
|
}
|
|
341
348
|
}
|
|
342
|
-
async function
|
|
349
|
+
async function readFile() {
|
|
343
350
|
// The file and access is validated before this method is called
|
|
344
351
|
const fileContents = (0, kit_1.parseJsonMap)(await fs.promises.readFile(getSecretFile(), 'utf8'));
|
|
345
352
|
return {
|
|
@@ -360,7 +367,7 @@ class GenericKeychainAccess {
|
|
|
360
367
|
if (fileAccessError == null) {
|
|
361
368
|
// read it's contents
|
|
362
369
|
try {
|
|
363
|
-
const { service, account, password } = await
|
|
370
|
+
const { service, account, password } = await readFile();
|
|
364
371
|
// validate service name and account just because
|
|
365
372
|
if (opts.service === service && opts.account === account) {
|
|
366
373
|
fn(null, password);
|
|
@@ -375,13 +382,11 @@ class GenericKeychainAccess {
|
|
|
375
382
|
fn(readJsonErr);
|
|
376
383
|
}
|
|
377
384
|
}
|
|
385
|
+
else if (fileAccessError.code === 'ENOENT') {
|
|
386
|
+
fn(messages.createError('passwordNotFoundError'));
|
|
387
|
+
}
|
|
378
388
|
else {
|
|
379
|
-
|
|
380
|
-
fn(messages.createError('passwordNotFoundError'));
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
fn(fileAccessError);
|
|
384
|
-
}
|
|
389
|
+
fn(fileAccessError);
|
|
385
390
|
}
|
|
386
391
|
});
|
|
387
392
|
}
|
|
@@ -393,7 +398,7 @@ class GenericKeychainAccess {
|
|
|
393
398
|
// file not found
|
|
394
399
|
if (fileAccessError.code === 'ENOENT') {
|
|
395
400
|
// create the file
|
|
396
|
-
await
|
|
401
|
+
await writeFile.call(this, opts, fn);
|
|
397
402
|
}
|
|
398
403
|
else {
|
|
399
404
|
fn(fileAccessError);
|
|
@@ -401,10 +406,11 @@ class GenericKeychainAccess {
|
|
|
401
406
|
}
|
|
402
407
|
else {
|
|
403
408
|
// the existing file validated. we can write the updated key
|
|
404
|
-
await
|
|
409
|
+
await writeFile.call(this, opts, fn);
|
|
405
410
|
}
|
|
406
411
|
});
|
|
407
412
|
}
|
|
413
|
+
// eslint-disable-next-line class-methods-use-this
|
|
408
414
|
async isValidFileAccess(cb) {
|
|
409
415
|
try {
|
|
410
416
|
const root = (0, os_1.homedir)();
|
|
@@ -436,6 +442,7 @@ class GenericUnixKeychainAccess extends GenericKeychainAccess {
|
|
|
436
442
|
await cb(null);
|
|
437
443
|
}
|
|
438
444
|
else {
|
|
445
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
439
446
|
cb(messages.createError('genericKeychainInvalidPermsError', [secretFile], [secretFile, EXPECTED_OCTAL_PERM_VALUE]));
|
|
440
447
|
}
|
|
441
448
|
}
|
|
@@ -473,8 +480,8 @@ exports.keyChainImpl = {
|
|
|
473
480
|
generic_unix: new GenericUnixKeychainAccess(),
|
|
474
481
|
// eslint-disable-next-line camelcase
|
|
475
482
|
generic_windows: new GenericWindowsKeychainAccess(),
|
|
476
|
-
darwin: new KeychainAccess(
|
|
477
|
-
linux: new KeychainAccess(
|
|
483
|
+
darwin: new KeychainAccess(darwinImpl, nodeFs),
|
|
484
|
+
linux: new KeychainAccess(linuxImpl, nodeFs),
|
|
478
485
|
validateProgram: _validateProgram,
|
|
479
486
|
};
|
|
480
487
|
//# sourceMappingURL=keyChainImpl.js.map
|
|
@@ -81,7 +81,7 @@ class DeviceOauthService extends kit_1.AsyncCreatable {
|
|
|
81
81
|
const deviceFlowRequestUrl = this.getDeviceFlowRequestUrl();
|
|
82
82
|
const pollingOptions = this.getPollingOptions(deviceFlowRequestUrl, loginData.device_code);
|
|
83
83
|
const interval = kit_1.Duration.seconds(loginData.interval).milliseconds;
|
|
84
|
-
return
|
|
84
|
+
return this.pollForDeviceApproval(pollingOptions, interval);
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
87
|
* Creates and saves new AuthInfo
|
|
@@ -138,7 +138,7 @@ class DeviceOauthService extends kit_1.AsyncCreatable {
|
|
|
138
138
|
return await makeRequest(httpRequest);
|
|
139
139
|
}
|
|
140
140
|
catch (e) {
|
|
141
|
-
|
|
141
|
+
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions */
|
|
142
142
|
const err = e.data;
|
|
143
143
|
if (err.error && err.status === 400 && err.error === 'authorization_pending') {
|
|
144
144
|
// do nothing because we're still waiting
|
|
@@ -153,6 +153,7 @@ class DeviceOauthService extends kit_1.AsyncCreatable {
|
|
|
153
153
|
}
|
|
154
154
|
throw err;
|
|
155
155
|
}
|
|
156
|
+
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions */
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
shouldContinuePolling() {
|
|
@@ -162,6 +163,7 @@ class DeviceOauthService extends kit_1.AsyncCreatable {
|
|
|
162
163
|
this.logger.debug('BEGIN POLLING FOR DEVICE APPROVAL');
|
|
163
164
|
let result;
|
|
164
165
|
while (this.shouldContinuePolling()) {
|
|
166
|
+
// eslint-disable-next-line no-await-in-loop
|
|
165
167
|
result = await this.poll(httpRequest);
|
|
166
168
|
if (result) {
|
|
167
169
|
this.logger.debug('POLLING FOR DEVICE APPROVAL SUCCESS');
|
|
@@ -169,6 +171,7 @@ class DeviceOauthService extends kit_1.AsyncCreatable {
|
|
|
169
171
|
}
|
|
170
172
|
else {
|
|
171
173
|
this.logger.debug(`waiting ${interval} ms...`);
|
|
174
|
+
// eslint-disable-next-line no-await-in-loop
|
|
172
175
|
await wait(interval);
|
|
173
176
|
this.pollingCount += 1;
|
|
174
177
|
}
|
package/lib/exported.js
CHANGED
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
9
|
if (k2 === undefined) k2 = k;
|
|
10
|
-
Object.
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
11
15
|
}) : (function(o, m, k, k2) {
|
|
12
16
|
if (k2 === undefined) k2 = k;
|
|
13
17
|
o[k2] = m[k];
|
package/lib/global.js
CHANGED
|
@@ -104,5 +104,7 @@ Global.STATE_FOLDER = Global.SFDX_STATE_FOLDER;
|
|
|
104
104
|
/**
|
|
105
105
|
* The full system path to the global log file.
|
|
106
106
|
*/
|
|
107
|
+
// member ordering conflicts with the TS use-before-declaration error
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/member-ordering
|
|
107
109
|
Global.LOG_FILE_PATH = path.join(Global.SF_DIR, 'sf.log');
|
|
108
110
|
//# sourceMappingURL=global.js.map
|
package/lib/lifecycleEvents.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.Lifecycle = void 0;
|
|
|
10
10
|
const Debug = require("debug");
|
|
11
11
|
const semver_1 = require("semver");
|
|
12
12
|
// needed for TS to not put everything inside /lib/src
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
13
14
|
// @ts-ignore
|
|
14
15
|
const pjson = require("../package.json");
|
|
15
16
|
/**
|
|
@@ -85,6 +86,7 @@ class Lifecycle {
|
|
|
85
86
|
/**
|
|
86
87
|
* return the package.json version of the sfdx-core library.
|
|
87
88
|
*/
|
|
89
|
+
// eslint-disable-next-line class-methods-use-this
|
|
88
90
|
version() {
|
|
89
91
|
return pjson.version;
|
|
90
92
|
}
|
|
@@ -175,6 +177,7 @@ class Lifecycle {
|
|
|
175
177
|
}
|
|
176
178
|
else {
|
|
177
179
|
for (const cb of listeners) {
|
|
180
|
+
// eslint-disable-next-line no-await-in-loop
|
|
178
181
|
await cb(data);
|
|
179
182
|
}
|
|
180
183
|
}
|
package/lib/logger.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export declare enum LoggerLevel {
|
|
|
62
62
|
FATAL = 60
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
65
|
+
* `Logger` format types.
|
|
66
66
|
*/
|
|
67
67
|
export declare enum LoggerFormat {
|
|
68
68
|
JSON = 0,
|
|
@@ -310,8 +310,7 @@ export declare class Logger {
|
|
|
310
310
|
/**
|
|
311
311
|
* Close the logger, including any streams, and remove all listeners.
|
|
312
312
|
*
|
|
313
|
-
* @param fn A function with signature `(stream: LoggerStream) => void` to call for each stream with
|
|
314
|
-
* the stream as an arg.
|
|
313
|
+
* @param fn A function with signature `(stream: LoggerStream) => void` to call for each stream with the stream as an arg.
|
|
315
314
|
*/
|
|
316
315
|
close(fn?: (stream: LoggerStream) => void): void;
|
|
317
316
|
/**
|
package/lib/logger.js
CHANGED
|
@@ -35,7 +35,7 @@ var LoggerLevel;
|
|
|
35
35
|
LoggerLevel[LoggerLevel["FATAL"] = 60] = "FATAL";
|
|
36
36
|
})(LoggerLevel = exports.LoggerLevel || (exports.LoggerLevel = {}));
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* `Logger` format types.
|
|
39
39
|
*/
|
|
40
40
|
var LoggerFormat;
|
|
41
41
|
(function (LoggerFormat) {
|
|
@@ -77,13 +77,13 @@ class Logger {
|
|
|
77
77
|
* The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
|
|
78
78
|
* See 'period' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
|
|
79
79
|
*/
|
|
80
|
-
this.logRotationPeriod = new kit_1.Env().getString('SF_LOG_ROTATION_PERIOD')
|
|
80
|
+
this.logRotationPeriod = new kit_1.Env().getString('SF_LOG_ROTATION_PERIOD') ?? '1d';
|
|
81
81
|
/**
|
|
82
82
|
* The number of backup rotated log files to keep.
|
|
83
83
|
* Example: '3' will have the base sf.log file, and the past 3 (period) log files.
|
|
84
84
|
* See 'count' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
|
|
85
85
|
*/
|
|
86
|
-
this.logRotationCount = new kit_1.Env().getNumber('SF_LOG_ROTATION_COUNT')
|
|
86
|
+
this.logRotationCount = new kit_1.Env().getNumber('SF_LOG_ROTATION_COUNT') ?? 2;
|
|
87
87
|
/**
|
|
88
88
|
* Whether debug is enabled for this Logger.
|
|
89
89
|
*/
|
|
@@ -118,7 +118,7 @@ class Logger {
|
|
|
118
118
|
}
|
|
119
119
|
// Inspect format to know what logging format to use then delete from options to
|
|
120
120
|
// ensure it doesn't conflict with Bunyan.
|
|
121
|
-
this.format = options.format
|
|
121
|
+
this.format = options.format ?? LoggerFormat.JSON;
|
|
122
122
|
delete options.format;
|
|
123
123
|
// If the log format is LOGFMT, we need to convert any stream(s) into a LOGFMT type stream.
|
|
124
124
|
if (this.format === LoggerFormat.LOGFMT && options.stream) {
|
|
@@ -139,7 +139,7 @@ class Logger {
|
|
|
139
139
|
this.bunyan.streams = [];
|
|
140
140
|
}
|
|
141
141
|
// all SFDX loggers must filter sensitive data
|
|
142
|
-
this.addFilter((...args) =>
|
|
142
|
+
this.addFilter((...args) => filterSecrets(...args));
|
|
143
143
|
if (global_1.Global.getEnvironmentMode() !== global_1.Mode.TEST) {
|
|
144
144
|
Logger.lifecycle.on('uncaughtException', this.uncaughtExceptionHandler);
|
|
145
145
|
Logger.lifecycle.on('exit', this.exitHandler);
|
|
@@ -363,7 +363,9 @@ class Logger {
|
|
|
363
363
|
/**
|
|
364
364
|
* Gets the underlying Bunyan logger.
|
|
365
365
|
*/
|
|
366
|
-
//
|
|
366
|
+
// leave this typed as any to keep if from trying to export the type from the untyped bunyan module
|
|
367
|
+
// this prevents consumers from getting node_modules/@salesforce/core/lib/logger.d.ts:281:24 - error TS2304: Cannot find name 'Bunyan'.
|
|
368
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
367
369
|
getBunyanLogger() {
|
|
368
370
|
return this.bunyan;
|
|
369
371
|
}
|
|
@@ -420,6 +422,7 @@ class Logger {
|
|
|
420
422
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
421
423
|
this.bunyan.streams.forEach(async (stream) => {
|
|
422
424
|
if (stream.type === 'file') {
|
|
425
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
423
426
|
content += await fs.promises.readFile(stream.path, 'utf8');
|
|
424
427
|
}
|
|
425
428
|
});
|
|
@@ -432,7 +435,6 @@ class Logger {
|
|
|
432
435
|
* @param filter A function with signature `(...args: any[]) => any[]` that transforms log message arguments.
|
|
433
436
|
*/
|
|
434
437
|
addFilter(filter) {
|
|
435
|
-
// eslint disable-line @typescript-eslint/no-explicit-any
|
|
436
438
|
if (!this.bunyan.filters) {
|
|
437
439
|
this.bunyan.filters = [];
|
|
438
440
|
}
|
|
@@ -441,8 +443,7 @@ class Logger {
|
|
|
441
443
|
/**
|
|
442
444
|
* Close the logger, including any streams, and remove all listeners.
|
|
443
445
|
*
|
|
444
|
-
* @param fn A function with signature `(stream: LoggerStream) => void` to call for each stream with
|
|
445
|
-
* the stream as an arg.
|
|
446
|
+
* @param fn A function with signature `(stream: LoggerStream) => void` to call for each stream with the stream as an arg.
|
|
446
447
|
*/
|
|
447
448
|
close(fn) {
|
|
448
449
|
if (this.bunyan.streams) {
|
|
@@ -500,6 +501,7 @@ class Logger {
|
|
|
500
501
|
*/
|
|
501
502
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
502
503
|
trace(...args) {
|
|
504
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
503
505
|
this.bunyan.trace(this.applyFilters(LoggerLevel.TRACE, ...args));
|
|
504
506
|
return this;
|
|
505
507
|
}
|
|
@@ -581,6 +583,7 @@ class Logger {
|
|
|
581
583
|
stream: new stream_1.Writable({
|
|
582
584
|
write: (chunk, encoding, next) => {
|
|
583
585
|
try {
|
|
586
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
584
587
|
const json = (0, kit_1.parseJsonMap)(chunk.toString());
|
|
585
588
|
const logLevel = (0, ts_types_1.ensureNumber)(json.level);
|
|
586
589
|
if (this.getLevel() <= logLevel) {
|
|
@@ -615,11 +618,14 @@ class Logger {
|
|
|
615
618
|
}
|
|
616
619
|
return args && args.length === 1 ? args[0] : args;
|
|
617
620
|
}
|
|
621
|
+
// eslint-disable-next-line class-methods-use-this
|
|
618
622
|
createLogFmtFormatterStream(loggerStream) {
|
|
619
623
|
const logFmtWriteableStream = new stream_1.Writable({
|
|
620
624
|
write: (chunk, enc, cb) => {
|
|
621
625
|
try {
|
|
626
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
622
627
|
const parsedJSON = JSON.parse(chunk.toString());
|
|
628
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
623
629
|
const keys = Object.keys(parsedJSON);
|
|
624
630
|
let logEntry = '';
|
|
625
631
|
keys.forEach((key) => {
|
|
@@ -682,50 +688,48 @@ const FILTERED_KEYS = [
|
|
|
682
688
|
{ name: 'sfdxauthurl', regex: 'sfdx[^\'"]*auth[^\'"]*url' },
|
|
683
689
|
];
|
|
684
690
|
// SFDX code and plugins should never show tokens or connect app information in the logs
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
_arg = '<Buffer>';
|
|
695
|
-
}
|
|
696
|
-
else if ((0, ts_types_1.isObject)(arg)) {
|
|
697
|
-
_arg = JSON.stringify(arg);
|
|
698
|
-
}
|
|
699
|
-
else if ((0, ts_types_1.isString)(arg)) {
|
|
700
|
-
_arg = arg;
|
|
701
|
-
}
|
|
702
|
-
else {
|
|
703
|
-
_arg = '';
|
|
704
|
-
}
|
|
705
|
-
const HIDDEN = 'HIDDEN';
|
|
706
|
-
FILTERED_KEYS.forEach((key) => {
|
|
707
|
-
let expElement = key;
|
|
708
|
-
let expName = key;
|
|
709
|
-
// Filtered keys can be strings or objects containing regular expression components.
|
|
710
|
-
if ((0, ts_types_1.isPlainObject)(key)) {
|
|
711
|
-
expElement = key.regex;
|
|
712
|
-
expName = key.name;
|
|
713
|
-
}
|
|
714
|
-
const hiddenAttrMessage = `"<${expName} - ${HIDDEN}>"`;
|
|
715
|
-
// Match all json attribute values case insensitive: ex. {" Access*^&(*()^* Token " : " 45143075913458901348905 \n\t" ...}
|
|
716
|
-
const regexTokens = new RegExp(`(['"][^'"]*${expElement}[^'"]*['"]\\s*:\\s*)['"][^'"]*['"]`, 'gi');
|
|
717
|
-
_arg = _arg.replace(regexTokens, `$1${hiddenAttrMessage}`);
|
|
718
|
-
// Match all key value attribute case insensitive: ex. {" key\t" : ' access_token ' , " value " : " dsafgasr431 " ....}
|
|
719
|
-
const keyRegex = new RegExp(`(['"]\\s*key\\s*['"]\\s*:)\\s*['"]\\s*${expElement}\\s*['"]\\s*.\\s*['"]\\s*value\\s*['"]\\s*:\\s*['"]\\s*[^'"]*['"]`, 'gi');
|
|
720
|
-
_arg = _arg.replace(keyRegex, `$1${hiddenAttrMessage}`);
|
|
721
|
-
});
|
|
722
|
-
_arg = _arg.replace(/(00D\w{12,15})![.\w]*/, `<${HIDDEN}>`);
|
|
723
|
-
// return an object if an object was logged; otherwise return the filtered string.
|
|
724
|
-
return (0, ts_types_1.isObject)(arg) ? (0, kit_1.parseJson)(_arg) : _arg;
|
|
691
|
+
const filterSecrets = (...args) => args.map((arg) => {
|
|
692
|
+
if ((0, ts_types_1.isArray)(arg)) {
|
|
693
|
+
return filterSecrets(...arg);
|
|
694
|
+
}
|
|
695
|
+
if (arg) {
|
|
696
|
+
let mutableArg;
|
|
697
|
+
// Normalize all objects into a string. This include errors.
|
|
698
|
+
if (arg instanceof Buffer) {
|
|
699
|
+
mutableArg = '<Buffer>';
|
|
725
700
|
}
|
|
726
|
-
else {
|
|
727
|
-
|
|
701
|
+
else if ((0, ts_types_1.isObject)(arg)) {
|
|
702
|
+
mutableArg = JSON.stringify(arg);
|
|
703
|
+
}
|
|
704
|
+
else if ((0, ts_types_1.isString)(arg)) {
|
|
705
|
+
mutableArg = arg;
|
|
728
706
|
}
|
|
729
|
-
|
|
730
|
-
|
|
707
|
+
else {
|
|
708
|
+
mutableArg = '';
|
|
709
|
+
}
|
|
710
|
+
const HIDDEN = 'HIDDEN';
|
|
711
|
+
FILTERED_KEYS.forEach((key) => {
|
|
712
|
+
let expElement = key;
|
|
713
|
+
let expName = key;
|
|
714
|
+
// Filtered keys can be strings or objects containing regular expression components.
|
|
715
|
+
if ((0, ts_types_1.isPlainObject)(key)) {
|
|
716
|
+
expElement = key.regex;
|
|
717
|
+
expName = key.name;
|
|
718
|
+
}
|
|
719
|
+
const hiddenAttrMessage = `"<${expName} - ${HIDDEN}>"`;
|
|
720
|
+
// Match all json attribute values case insensitive: ex. {" Access*^&(*()^* Token " : " 45143075913458901348905 \n\t" ...}
|
|
721
|
+
const regexTokens = new RegExp(`(['"][^'"]*${expElement}[^'"]*['"]\\s*:\\s*)['"][^'"]*['"]`, 'gi');
|
|
722
|
+
mutableArg = mutableArg.replace(regexTokens, `$1${hiddenAttrMessage}`);
|
|
723
|
+
// Match all key value attribute case insensitive: ex. {" key\t" : ' access_token ' , " value " : " dsafgasr431 " ....}
|
|
724
|
+
const keyRegex = new RegExp(`(['"]\\s*key\\s*['"]\\s*:)\\s*['"]\\s*${expElement}\\s*['"]\\s*.\\s*['"]\\s*value\\s*['"]\\s*:\\s*['"]\\s*[^'"]*['"]`, 'gi');
|
|
725
|
+
mutableArg = mutableArg.replace(keyRegex, `$1${hiddenAttrMessage}`);
|
|
726
|
+
});
|
|
727
|
+
mutableArg = mutableArg.replace(/(00D\w{12,15})![.\w]*/, `<${HIDDEN}>`);
|
|
728
|
+
// return an object if an object was logged; otherwise return the filtered string.
|
|
729
|
+
return (0, ts_types_1.isObject)(arg) ? (0, kit_1.parseJson)(mutableArg) : mutableArg;
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
return arg;
|
|
733
|
+
}
|
|
734
|
+
});
|
|
731
735
|
//# sourceMappingURL=logger.js.map
|
package/lib/messages.js
CHANGED
|
@@ -539,7 +539,6 @@ Messages.bundles = new Map();
|
|
|
539
539
|
* @param filePath read file target.
|
|
540
540
|
* @ignore
|
|
541
541
|
*/
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
};
|
|
542
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
543
|
+
Messages.readFile = (filePath) => require(filePath);
|
|
545
544
|
//# sourceMappingURL=messages.js.map
|