@salesforce/core 8.25.0 → 8.26.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.
@@ -169,6 +169,11 @@ class ConfigFile extends configStore_1.BaseConfigStore {
169
169
  return this.getContents();
170
170
  }
171
171
  }
172
+ else if (err.name === 'JsonParseError') {
173
+ this.logger.debug(`Contents of ${this.getPath()} could not be parsed as JSON. Using empty object instead.`);
174
+ this.setContentsFromObject({});
175
+ return this.getContents();
176
+ }
172
177
  // Necessarily set this even when an error happens to avoid infinite re-reading.
173
178
  // To attempt another read, pass `force=true`.
174
179
  throw err;
@@ -365,6 +370,9 @@ class ConfigFile extends configStore_1.BaseConfigStore {
365
370
  if (err instanceof Error && err.message.includes('ENOENT')) {
366
371
  this.logger.debug(`No file found at ${this.getPath()}. Write will create it.`);
367
372
  }
373
+ else if (err instanceof Error && err.name === 'JsonParseError') {
374
+ this.logger.debug(`Could not parse ${this.getPath()} as JSON. Existing contents will be replaced.`);
375
+ }
368
376
  else {
369
377
  throw err;
370
378
  }
@@ -17,6 +17,7 @@ const buildKeyRegex = (expElement) => RegExp(`(['"]\\s*key\\s*['"]\\s*:)\\s*['"]
17
17
  // This will redact values when the keys match certain patterns
18
18
  const FILTERED_KEYS = [
19
19
  { name: 'sid' },
20
+ { name: 'jwt' },
20
21
  { name: 'Authorization' },
21
22
  // Any json attribute that contains the words "refresh" and "token" will have the attribute/value hidden
22
23
  { name: 'refresh_token', regex: 'refresh[^\'"]*token' },
@@ -39,6 +40,7 @@ const replacementFunctions = FILTERED_KEYS_FOR_PROCESSING.flatMap((key) => [
39
40
  // use these for secrets with known patterns
40
41
  (input) => input
41
42
  .replace(new RegExp(sfdc_1.accessTokenRegex, 'g'), '<REDACTED ACCESS TOKEN>')
43
+ .replace(new RegExp(sfdc_1.jwtTokenRegex, 'g'), '<REDACTED JWT TOKEN>')
42
44
  .replace(new RegExp(sfdc_1.sfdxAuthUrlRegex, 'g'), '<REDACTED AUTH URL TOKEN>'),
43
45
  // conditional replacement for clientId: leave the value if it's the PlatformCLI, otherwise redact it
44
46
  (input) => input.replace(/(['"]client.*Id['"])\s*:\s*(['"][^'"]*['"])/gi, (all, key, value) => value.includes('PlatformCLI') ? `${key}:${value}` : `${key}:"<REDACTED CLIENT ID>"`),
@@ -33,7 +33,6 @@ export type AuthFields = {
33
33
  password?: string;
34
34
  privateKey?: string;
35
35
  refreshToken?: string;
36
- scratchAdminUsername?: string;
37
36
  snapshot?: string;
38
37
  userId?: string;
39
38
  username?: string;
@@ -425,7 +425,7 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
425
425
  async save(authData) {
426
426
  this.update(authData);
427
427
  const username = (0, ts_types_1.ensure)(this.getUsername());
428
- if ((0, sfdc_1.matchesAccessToken)(username)) {
428
+ if ((0, sfdc_1.matchesOpaqueAccessToken)(username)) {
429
429
  this.logger.debug('Username is an accesstoken. Skip saving authinfo to disk.');
430
430
  return this;
431
431
  }
@@ -662,7 +662,7 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
662
662
  await this.stateAggregator.orgs.read(oauthUsername, false, false);
663
663
  } // Else it will be set in initAuthOptions below.
664
664
  // If the username is an access token, use that for auth and don't persist
665
- if ((0, ts_types_1.isString)(oauthUsername) && (0, sfdc_1.matchesAccessToken)(oauthUsername)) {
665
+ if ((0, ts_types_1.isString)(oauthUsername) && (0, sfdc_1.matchesOpaqueAccessToken)(oauthUsername)) {
666
666
  // Need to initAuthOptions the logger and authInfoCrypto since we don't call init()
667
667
  this.logger = await logger_1.Logger.child('AuthInfo');
668
668
  const aggregator = await configAggregator_1.ConfigAggregator.create();
package/lib/org/user.js CHANGED
@@ -437,7 +437,7 @@ class User extends kit_1.AsyncCreatable {
437
437
  }
438
438
  exports.User = User;
439
439
  const resolveUsernameFromAccessToken = (logger) => (conn) => async (usernameOrAccessToken) => {
440
- if ((0, sfdc_1.matchesAccessToken)(usernameOrAccessToken)) {
440
+ if ((0, sfdc_1.matchesOpaqueAccessToken)(usernameOrAccessToken)) {
441
441
  logger.debug('received an accessToken for the username. Converting...');
442
442
  const username = (await conn.identity()).username;
443
443
  logger.debug(`accessToken converted to ${username}`);
@@ -264,6 +264,7 @@ exports.simpleFeaturesList = [
264
264
  'TimelineRecordTypeLimit',
265
265
  'TransactionFinalizers',
266
266
  'UsageManagement',
267
+ 'VolunteerManagement',
267
268
  'Walkthroughs',
268
269
  'WaveMaxCurrency',
269
270
  'WavePlatform',
@@ -31,10 +31,23 @@ export declare const validateSalesforceId: (value: string) => boolean;
31
31
  */
32
32
  export declare const validatePathDoesNotContainInvalidChars: (value: string) => boolean;
33
33
  export declare const accessTokenRegex: RegExp;
34
+ export declare const jwtTokenRegex: RegExp;
34
35
  export declare const sfdxAuthUrlRegex: RegExp;
35
36
  /**
36
- * Tests whether a given string is an access token
37
+ * Tests whether a given string is an opaque access token, a JWT token, or neither.
37
38
  *
38
39
  * @param value
39
40
  */
40
- export declare const matchesAccessToken: (value: string) => boolean;
41
+ export declare function matchesAccessToken(value: string): boolean;
42
+ /**
43
+ * Tests whether a given string is an opaque access token.
44
+ *
45
+ * @param value
46
+ */
47
+ export declare const matchesOpaqueAccessToken: (value: string) => boolean;
48
+ /**
49
+ * Tests whether a given string is a JWT-formatted access token.
50
+ *
51
+ * @param value
52
+ */
53
+ export declare const matchesJwtAccessToken: (value: string) => boolean;
package/lib/util/sfdc.js CHANGED
@@ -6,8 +6,9 @@
6
6
  * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.matchesAccessToken = exports.sfdxAuthUrlRegex = exports.accessTokenRegex = exports.validatePathDoesNotContainInvalidChars = exports.validateSalesforceId = exports.validateEmail = exports.validateApiVersion = void 0;
9
+ exports.matchesJwtAccessToken = exports.matchesOpaqueAccessToken = exports.sfdxAuthUrlRegex = exports.jwtTokenRegex = exports.accessTokenRegex = exports.validatePathDoesNotContainInvalidChars = exports.validateSalesforceId = exports.validateEmail = exports.validateApiVersion = void 0;
10
10
  exports.trimTo15 = trimTo15;
11
+ exports.matchesAccessToken = matchesAccessToken;
11
12
  function trimTo15(id) {
12
13
  if (!id) {
13
14
  return undefined;
@@ -48,12 +49,52 @@ const validatePathDoesNotContainInvalidChars = (value) =>
48
49
  !/[\["\?<>\|\]]+/.test(value);
49
50
  exports.validatePathDoesNotContainInvalidChars = validatePathDoesNotContainInvalidChars;
50
51
  exports.accessTokenRegex = /(00D\w{12,15})![.\w]*/;
52
+ // 'eyJ' strongly suggests that this is a base64 JSON, and so the general shape of the rest of it is enough to presume it's a JWT.
53
+ exports.jwtTokenRegex = /eyJ[A-Za-z0-9+=_-]+\.[A-Za-z0-9+=_-]+\.[A-Za-z0-9+=_-]+/;
51
54
  exports.sfdxAuthUrlRegex = /force:\/\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]*):([a-zA-Z0-9._-]+={0,2})@([a-zA-Z0-9._-]+)/;
52
55
  /**
53
- * Tests whether a given string is an access token
56
+ * Tests whether a given string is an opaque access token, a JWT token, or neither.
54
57
  *
55
58
  * @param value
56
59
  */
57
- const matchesAccessToken = (value) => exports.accessTokenRegex.test(value);
58
- exports.matchesAccessToken = matchesAccessToken;
60
+ function matchesAccessToken(value) {
61
+ return (0, exports.matchesOpaqueAccessToken)(value) || (0, exports.matchesJwtAccessToken)(value);
62
+ }
63
+ /**
64
+ * Tests whether a given string is an opaque access token.
65
+ *
66
+ * @param value
67
+ */
68
+ const matchesOpaqueAccessToken = (value) => exports.accessTokenRegex.test(value);
69
+ exports.matchesOpaqueAccessToken = matchesOpaqueAccessToken;
70
+ /**
71
+ * Tests whether a given string is a JWT-formatted access token.
72
+ *
73
+ * @param value
74
+ */
75
+ const matchesJwtAccessToken = (value) => {
76
+ const segments = value.split('.');
77
+ if (segments.length !== 3) {
78
+ return false;
79
+ }
80
+ if (!isValidJson(segments[0], true)) {
81
+ return false;
82
+ }
83
+ return isValidJson(segments[1], false);
84
+ };
85
+ exports.matchesJwtAccessToken = matchesJwtAccessToken;
86
+ const isValidJson = (str, checkForTyp) => {
87
+ try {
88
+ const parsedJson = JSON.parse(Buffer.from(str, 'base64').toString('utf-8'));
89
+ if (checkForTyp) {
90
+ return 'typ' in parsedJson && parsedJson.typ === 'JWT';
91
+ }
92
+ else {
93
+ return true;
94
+ }
95
+ }
96
+ catch (e) {
97
+ return false;
98
+ }
99
+ };
59
100
  //# sourceMappingURL=sfdc.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/core",
3
- "version": "8.25.0",
3
+ "version": "8.26.0",
4
4
  "description": "Core libraries to interact with SFDX projects, orgs, and APIs.",
5
5
  "main": "lib/index",
6
6
  "types": "lib/index.d.ts",
@@ -604,6 +604,7 @@
604
604
  "TimelineRecordTypeLimit",
605
605
  "TransactionFinalizers",
606
606
  "UsageManagement",
607
+ "VolunteerManagement",
607
608
  "Walkthroughs",
608
609
  "WaveMaxCurrency",
609
610
  "WavePlatform",