@salesforce/core 6.5.6 → 6.7.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.
@@ -2,8 +2,9 @@ import { SandboxProcessObject, SandboxRequest } from '../org/org';
2
2
  import { TTLConfig } from './ttlConfig';
3
3
  export type SandboxRequestCacheEntry = {
4
4
  alias?: string;
5
- setDefault: boolean;
5
+ setDefault?: boolean;
6
6
  prodOrgUsername: string;
7
+ action: 'Create' | 'Refresh';
7
8
  sandboxProcessObject: Partial<SandboxProcessObject>;
8
9
  sandboxRequest: Partial<SandboxRequest>;
9
10
  tracksSource?: boolean;
@@ -21,6 +21,7 @@ export declare class Crypto extends AsyncOptionalCreatable<CryptoOptions> {
21
21
  * @ignore
22
22
  */
23
23
  constructor(options?: CryptoOptions);
24
+ private static unsetCryptoVersion;
24
25
  /**
25
26
  * Encrypts text. Returns the encrypted string or undefined if no string was passed.
26
27
  *
@@ -45,10 +46,15 @@ export declare class Crypto extends AsyncOptionalCreatable<CryptoOptions> {
45
46
  * Clears the crypto state. This should be called in a finally block.
46
47
  */
47
48
  close(): void;
49
+ isV2Crypto(): boolean;
48
50
  /**
49
51
  * Initialize async components.
50
52
  */
51
53
  protected init(): Promise<void>;
54
+ private encryptV1;
55
+ private encryptV2;
56
+ private decryptV1;
57
+ private decryptV2;
52
58
  private getKeyChain;
53
59
  }
54
60
  export {};
@@ -37,23 +37,96 @@ const node_path_1 = require("node:path");
37
37
  const ts_types_1 = require("@salesforce/ts-types");
38
38
  const kit_1 = require("@salesforce/kit");
39
39
  const logger_1 = require("../logger/logger");
40
+ const lifecycleEvents_1 = require("../lifecycleEvents");
40
41
  const messages_1 = require("../messages");
41
42
  const cache_1 = require("../util/cache");
42
43
  const global_1 = require("../global");
44
+ const sfError_1 = require("../sfError");
43
45
  const keyChain_1 = require("./keyChain");
44
46
  const secureBuffer_1 = require("./secureBuffer");
45
47
  const TAG_DELIMITER = ':';
46
- const BYTE_COUNT_FOR_IV = 6;
48
+ const IV_BYTES = {
49
+ v1: 6,
50
+ v2: 12,
51
+ };
52
+ const ENCODING = {
53
+ v1: 'utf8',
54
+ v2: 'hex',
55
+ };
56
+ const KEY_SIZE = {
57
+ v1: 16,
58
+ v2: 32,
59
+ };
47
60
  const ALGO = 'aes-256-gcm';
48
61
  const AUTH_TAG_LENGTH = 32;
49
62
  const ENCRYPTED_CHARS = /[a-f0-9]/;
50
63
  const KEY_NAME = 'sfdx';
51
64
  const ACCOUNT = 'local';
65
+ let cryptoLogger;
66
+ const getCryptoLogger = () => {
67
+ cryptoLogger ??= logger_1.Logger.childFromRoot('crypto');
68
+ return cryptoLogger;
69
+ };
70
+ const getCryptoV2EnvVar = () => {
71
+ let sfCryptoV2 = process.env.SF_CRYPTO_V2?.toLowerCase();
72
+ if (sfCryptoV2 !== undefined) {
73
+ getCryptoLogger().debug(`SF_CRYPTO_V2=${sfCryptoV2}`);
74
+ // normalize all values that aren't "true" to be "false"
75
+ if (sfCryptoV2 !== 'true') {
76
+ sfCryptoV2 = 'false';
77
+ }
78
+ }
79
+ return sfCryptoV2;
80
+ };
81
+ let cryptoVersion;
82
+ const getCryptoVersion = () => {
83
+ if (!cryptoVersion) {
84
+ // This only happens when generating a new key, so use the env var
85
+ // and (for now) default to 'v1'.
86
+ cryptoVersion = getCryptoV2EnvVar() === 'true' ? 'v2' : 'v1';
87
+ }
88
+ return cryptoVersion;
89
+ };
90
+ // Detect the crypto version based on the password (key) length.
91
+ // This happens once per process.
92
+ const detectCryptoVersion = (pwd) => {
93
+ if (!cryptoVersion) {
94
+ // check the env var to see if it's set
95
+ const sfCryptoV2 = getCryptoV2EnvVar();
96
+ // Password length of 64 is v2 crypto and uses hex encoding.
97
+ // Password length of 32 is v1 crypto and uses utf8 encoding.
98
+ if (pwd?.length === KEY_SIZE.v2 * 2) {
99
+ cryptoVersion = 'v2';
100
+ getCryptoLogger().debug('Using v2 crypto');
101
+ if (sfCryptoV2 === 'false') {
102
+ getCryptoLogger().warn(messages.getMessage('v1CryptoWithV2KeyWarning'));
103
+ }
104
+ }
105
+ else if (pwd?.length === KEY_SIZE.v1 * 2) {
106
+ cryptoVersion = 'v1';
107
+ getCryptoLogger().debug('Using v1 crypto');
108
+ if (sfCryptoV2 === 'true') {
109
+ getCryptoLogger().warn(messages.getMessage('v2CryptoWithV1KeyWarning'));
110
+ }
111
+ }
112
+ else {
113
+ getCryptoLogger().debug("crypto key doesn't match v1 or v2. using SF_CRYPTO_V2.");
114
+ getCryptoVersion();
115
+ }
116
+ void lifecycleEvents_1.Lifecycle.getInstance().emitTelemetry({
117
+ eventName: 'crypto_version',
118
+ library: 'sfdx-core',
119
+ function: 'detectCryptoVersion',
120
+ cryptoVersion, // 'v1' or 'v2'
121
+ cryptoEnvVar: sfCryptoV2, // 'true' or 'false' or 'undefined'
122
+ });
123
+ }
124
+ };
52
125
  ;
53
- const messages = new messages_1.Messages('@salesforce/core', 'encryption', new Map([["invalidEncryptedFormatError", "The encrypted data is not properly formatted."], ["invalidEncryptedFormatError.actions", ["If attempting to create a scratch org then re-authorize. Otherwise create a new scratch org."]], ["authDecryptError", "Failed to decipher auth data. reason: %s."], ["unsupportedOperatingSystemError", "Unsupported Operating System: %s"], ["missingCredentialProgramError", "Unable to find required security software: %s"], ["credentialProgramAccessError", "Unable to execute security software: %s"], ["passwordRetryError", "Failed to get the password after %i retries."], ["passwordRequiredError", "A password is required."], ["keyChainServiceRequiredError", "Unable to get or set a keychain value without a service name."], ["keyChainAccountRequiredError", "Unable to get or set a keychain value without an account name."], ["keyChainUserCanceledError", "User canceled authentication."], ["keychainPasswordCreationError", "Failed to create a password in the keychain."], ["genericKeychainServiceError", "The service and account specified in %s do not match the version of the toolbelt."], ["genericKeychainServiceError.actions", ["Check your toolbelt version and re-auth."]], ["genericKeychainInvalidPermsError", "Invalid file permissions for secret file"], ["genericKeychainInvalidPermsError.actions", ["Ensure the file %s has the file permission octal value of %s."]], ["passwordNotFoundError", "Could not find password.\n%s"], ["passwordNotFoundError.actions", ["Ensure a valid password is returned with the following command: [%s]"]], ["setCredentialError", "Command failed with response:\n%s"], ["setCredentialError.actions", ["Determine why this command failed to set an encryption key for user %s: [%s]."]], ["macKeychainOutOfSync", "We\u2019ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands."]]));
54
- const makeSecureBuffer = (password) => {
126
+ const messages = new messages_1.Messages('@salesforce/core', 'encryption', new Map([["invalidEncryptedFormatError", "The encrypted data is not properly formatted."], ["invalidEncryptedFormatError.actions", ["If attempting to create a scratch org then re-authorize. Otherwise create a new scratch org."]], ["authDecryptError", "Failed to decipher auth data. reason: %s."], ["unsupportedOperatingSystemError", "Unsupported Operating System: %s"], ["missingCredentialProgramError", "Unable to find required security software: %s"], ["credentialProgramAccessError", "Unable to execute security software: %s"], ["passwordRetryError", "Failed to get the password after %i retries."], ["passwordRequiredError", "A password is required."], ["keyChainServiceRequiredError", "Unable to get or set a keychain value without a service name."], ["keyChainAccountRequiredError", "Unable to get or set a keychain value without an account name."], ["keyChainUserCanceledError", "User canceled authentication."], ["keychainPasswordCreationError", "Failed to create a password in the keychain."], ["genericKeychainServiceError", "The service and account specified in %s do not match the version of the toolbelt."], ["genericKeychainServiceError.actions", ["Check your toolbelt version and re-auth."]], ["genericKeychainInvalidPermsError", "Invalid file permissions for secret file"], ["genericKeychainInvalidPermsError.actions", ["Ensure the file %s has the file permission octal value of %s."]], ["passwordNotFoundError", "Could not find password.\n%s"], ["passwordNotFoundError.actions", ["Ensure a valid password is returned with the following command: [%s]"]], ["setCredentialError", "Command failed with response:\n%s"], ["setCredentialError.actions", ["Determine why this command failed to set an encryption key for user %s: [%s]."]], ["macKeychainOutOfSync", "We\u2019ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands."], ["v1CryptoWithV2KeyWarning", "The SF_CRYPTO_V2 environment variable was set to \"false\" but a v2 crypto key was detected. v1 crypto can only be used with a v1 key. Unset the SF_CRYPTO_V2 environment variable."], ["v2CryptoWithV1KeyWarning", "SF_CRYPTO_V2 was set to \"true\" but a v1 crypto key was detected. v2 crypto can only be used with a v2 key. To generate a v2 key:\n\n1. Logout of all orgs: `sf org logout --all`\n2. Delete the sfdx keychain entry (account: local, service: sfdx). If `SF_USE_GENERIC_UNIX_KEYCHAIN=true` env var is set, you can delete the `key.json` file.\n3. Set `SF_CRYPTO_V2=true` env var.\n4. Re-Authenticate with your orgs using the CLI org login commands."]]));
127
+ const makeSecureBuffer = (password, encoding) => {
55
128
  const newSb = new secureBuffer_1.SecureBuffer();
56
- newSb.consume(Buffer.from((0, ts_types_1.ensure)(password), 'utf8'));
129
+ newSb.consume(Buffer.from(password, encoding));
57
130
  return newSb;
58
131
  };
59
132
  /**
@@ -74,14 +147,19 @@ const keychainPromises = {
74
147
  return new Promise((resolve, reject) => _keychain.getPassword({ service, account }, (err, password) => {
75
148
  if (err)
76
149
  return reject(err);
77
- cache_1.Cache.set(cacheKey, makeSecureBuffer(password));
78
- return resolve({ username: account, password: (0, ts_types_1.ensure)(password) });
150
+ const pwd = (0, ts_types_1.ensure)(password, 'Expected the keychain password to be set');
151
+ detectCryptoVersion(pwd);
152
+ cache_1.Cache.set(cacheKey, makeSecureBuffer(pwd, ENCODING[getCryptoVersion()]));
153
+ return resolve({ username: account, password: pwd });
79
154
  }));
80
155
  }
81
156
  else {
82
- const pw = sb.value((buffer) => buffer.toString('utf8'));
83
- cache_1.Cache.set(cacheKey, makeSecureBuffer(pw));
84
- return new Promise((resolve) => resolve({ username: account, password: (0, ts_types_1.ensure)(pw) }));
157
+ // If the password is cached, we know the crypto version and encoding because it was
158
+ // detected by the non-cache code path just above this.
159
+ const encoding = ENCODING[getCryptoVersion()];
160
+ const pwd = (0, ts_types_1.ensure)(sb.value((buffer) => buffer.toString(encoding)), 'Expected the keychain password to be set');
161
+ cache_1.Cache.set(cacheKey, makeSecureBuffer(pwd, encoding));
162
+ return new Promise((resolve) => resolve({ username: account, password: pwd }));
85
163
  }
86
164
  },
87
165
  /**
@@ -116,6 +194,11 @@ class Crypto extends kit_1.AsyncOptionalCreatable {
116
194
  this.key = new secureBuffer_1.SecureBuffer();
117
195
  this.options = options ?? {};
118
196
  }
197
+ // @ts-expect-error only for test access
198
+ // eslint-disable-next-line class-methods-use-this
199
+ static unsetCryptoVersion() {
200
+ cryptoVersion = undefined;
201
+ }
119
202
  encrypt(text) {
120
203
  if (text == null) {
121
204
  return;
@@ -123,14 +206,13 @@ class Crypto extends kit_1.AsyncOptionalCreatable {
123
206
  if (this.key == null) {
124
207
  throw messages.createError('keychainPasswordCreationError');
125
208
  }
126
- const iv = crypto.randomBytes(BYTE_COUNT_FOR_IV).toString('hex');
127
- return this.key.value((buffer) => {
128
- const cipher = crypto.createCipheriv(ALGO, buffer.toString('utf8'), iv);
129
- let encrypted = cipher.update(text, 'utf8', 'hex');
130
- encrypted += cipher.final('hex');
131
- const tag = cipher.getAuthTag().toString('hex');
132
- return `${iv}${encrypted}${TAG_DELIMITER}${tag}`;
133
- });
209
+ // When everything is v2, we can remove the else
210
+ if (this.isV2Crypto()) {
211
+ return this.encryptV2(text);
212
+ }
213
+ else {
214
+ return this.encryptV1(text);
215
+ }
134
216
  }
135
217
  decrypt(text) {
136
218
  if (text == null) {
@@ -140,27 +222,13 @@ class Crypto extends kit_1.AsyncOptionalCreatable {
140
222
  if (tokens.length !== 2) {
141
223
  throw messages.createError('invalidEncryptedFormatError');
142
224
  }
143
- const tag = tokens[1];
144
- const iv = tokens[0].substring(0, BYTE_COUNT_FOR_IV * 2);
145
- const secret = tokens[0].substring(BYTE_COUNT_FOR_IV * 2, tokens[0].length);
146
- return this.key.value((buffer) => {
147
- const decipher = crypto.createDecipheriv(ALGO, buffer.toString('utf8'), iv);
148
- let dec;
149
- try {
150
- decipher.setAuthTag(Buffer.from(tag, 'hex'));
151
- dec = decipher.update(secret, 'hex', 'utf8');
152
- dec += decipher.final('utf8');
153
- }
154
- catch (err) {
155
- const error = messages.createError('authDecryptError', [err.message], [], err);
156
- const useGenericUnixKeychain = kit_1.env.getBoolean('SF_USE_GENERIC_UNIX_KEYCHAIN') || kit_1.env.getBoolean('USE_GENERIC_UNIX_KEYCHAIN');
157
- if (os.platform() === 'darwin' && !useGenericUnixKeychain) {
158
- error.actions = [messages.getMessage('macKeychainOutOfSync')];
159
- }
160
- throw error;
161
- }
162
- return dec;
163
- });
225
+ // When everything is v2, we can remove the else
226
+ if (this.isV2Crypto()) {
227
+ return this.decryptV2(tokens);
228
+ }
229
+ else {
230
+ return this.decryptV1(tokens);
231
+ }
164
232
  }
165
233
  /**
166
234
  * Takes a best guess if the value provided was encrypted by {@link Crypto.encrypt} by
@@ -181,7 +249,7 @@ class Crypto extends kit_1.AsyncOptionalCreatable {
181
249
  const tag = tokens[1];
182
250
  const value = tokens[0];
183
251
  return (tag.length === AUTH_TAG_LENGTH &&
184
- value.length >= BYTE_COUNT_FOR_IV &&
252
+ value.length >= IV_BYTES[getCryptoVersion()] &&
185
253
  ENCRYPTED_CHARS.test(tag) &&
186
254
  ENCRYPTED_CHARS.test(tokens[0]));
187
255
  }
@@ -193,33 +261,39 @@ class Crypto extends kit_1.AsyncOptionalCreatable {
193
261
  this.key.clear();
194
262
  }
195
263
  }
264
+ // eslint-disable-next-line class-methods-use-this
265
+ isV2Crypto() {
266
+ return getCryptoVersion() === 'v2';
267
+ }
196
268
  /**
197
269
  * Initialize async components.
198
270
  */
199
271
  async init() {
200
- const logger = await logger_1.Logger.child('crypto');
201
272
  if (!this.options.platform) {
202
273
  this.options.platform = os.platform();
203
274
  }
204
- logger.debug(`retryStatus: ${this.options.retryStatus}`);
205
275
  this.noResetOnClose = !!this.options.noResetOnClose;
206
276
  try {
207
- this.key.consume(Buffer.from((await keychainPromises.getPassword(await this.getKeyChain(this.options.platform), KEY_NAME, ACCOUNT))
208
- .password, 'utf8'));
277
+ const keyChain = await this.getKeyChain(this.options.platform);
278
+ const pwd = (await keychainPromises.getPassword(keyChain, KEY_NAME, ACCOUNT)).password;
279
+ // The above line ensures the crypto version is detected and set so we can rely on it now.
280
+ this.key.consume(Buffer.from(pwd, ENCODING[getCryptoVersion()]));
209
281
  }
210
282
  catch (err) {
211
283
  // No password found
212
284
  if (err.name === 'PasswordNotFoundError') {
213
285
  // If we already tried to create a new key then bail.
214
286
  if (this.options.retryStatus === 'KEY_SET') {
215
- logger.debug('a key was set but the retry to get the password failed.');
287
+ getCryptoLogger().debug('a key was set but the retry to get the password failed.');
216
288
  throw err;
217
289
  }
218
290
  else {
219
- logger.debug('password not found in keychain attempting to created one and re-init.');
291
+ getCryptoLogger().debug(`password not found in keychain. Creating new one (Crypto ${getCryptoVersion()}) and re-init.`);
220
292
  }
221
- const key = crypto.randomBytes(Math.ceil(16)).toString('hex');
222
- // Create a new password in the KeyChain.
293
+ // 2/6/2024: This generates a new key using the crypto version based on the SF_CRYPTO_V2 env var.
294
+ // Sometime in the future we could hardcode this to be `KEY_SIZE.v2` so that it becomes the default.
295
+ const key = crypto.randomBytes(KEY_SIZE[getCryptoVersion()]).toString('hex');
296
+ // Set the new password in the KeyChain.
223
297
  await keychainPromises.setPassword((0, ts_types_1.ensure)(this.options.keychain), KEY_NAME, ACCOUNT, key);
224
298
  return this.init();
225
299
  }
@@ -228,6 +302,68 @@ class Crypto extends kit_1.AsyncOptionalCreatable {
228
302
  }
229
303
  }
230
304
  }
305
+ encryptV1(text) {
306
+ const iv = crypto.randomBytes(IV_BYTES.v1).toString('hex');
307
+ return this.key.value((buffer) => {
308
+ const cipher = crypto.createCipheriv(ALGO, buffer.toString('utf8'), iv);
309
+ let encrypted = cipher.update(text, 'utf8', 'hex');
310
+ encrypted += cipher.final('hex');
311
+ const tag = cipher.getAuthTag().toString('hex');
312
+ return `${iv}${encrypted}${TAG_DELIMITER}${tag}`;
313
+ });
314
+ }
315
+ encryptV2(text) {
316
+ const iv = crypto.randomBytes(IV_BYTES.v2);
317
+ return this.key.value((buffer) => {
318
+ const cipher = crypto.createCipheriv(ALGO, buffer, iv);
319
+ const ivHex = iv.toString('hex');
320
+ let encrypted = cipher.update(text, 'utf8', 'hex');
321
+ encrypted += cipher.final('hex');
322
+ const tag = cipher.getAuthTag().toString('hex');
323
+ return `${ivHex}${encrypted}${TAG_DELIMITER}${tag}`;
324
+ });
325
+ }
326
+ decryptV1(tokens) {
327
+ const tag = tokens[1];
328
+ const iv = tokens[0].substring(0, IV_BYTES.v1 * 2);
329
+ const secret = tokens[0].substring(IV_BYTES.v1 * 2, tokens[0].length);
330
+ return this.key.value((buffer) => {
331
+ const decipher = crypto.createDecipheriv(ALGO, buffer.toString('utf8'), iv);
332
+ try {
333
+ decipher.setAuthTag(Buffer.from(tag, 'hex'));
334
+ return `${decipher.update(secret, 'hex', 'utf8')}${decipher.final('utf8')}`;
335
+ }
336
+ catch (err) {
337
+ const error = messages.createError('authDecryptError', [err.message], [], err);
338
+ const useGenericUnixKeychain = kit_1.env.getBoolean('SF_USE_GENERIC_UNIX_KEYCHAIN') || kit_1.env.getBoolean('USE_GENERIC_UNIX_KEYCHAIN');
339
+ if (os.platform() === 'darwin' && !useGenericUnixKeychain) {
340
+ error.actions = [messages.getMessage('macKeychainOutOfSync')];
341
+ }
342
+ throw error;
343
+ }
344
+ });
345
+ }
346
+ decryptV2(tokens) {
347
+ const tag = tokens[1];
348
+ const iv = tokens[0].substring(0, IV_BYTES.v2 * 2);
349
+ const secret = tokens[0].substring(IV_BYTES.v2 * 2, tokens[0].length);
350
+ return this.key.value((buffer) => {
351
+ const decipher = crypto.createDecipheriv(ALGO, buffer, Buffer.from(iv, 'hex'));
352
+ try {
353
+ decipher.setAuthTag(Buffer.from(tag, 'hex'));
354
+ return `${decipher.update(secret, 'hex', 'utf8')}${decipher.final('utf8')}`;
355
+ }
356
+ catch (_err) {
357
+ const err = ((0, ts_types_1.isString)(_err) ? sfError_1.SfError.wrap(_err) : _err);
358
+ const error = messages.createError('authDecryptError', [err.message], [], err);
359
+ const useGenericUnixKeychain = kit_1.env.getBoolean('SF_USE_GENERIC_UNIX_KEYCHAIN') || kit_1.env.getBoolean('USE_GENERIC_UNIX_KEYCHAIN');
360
+ if (os.platform() === 'darwin' && !useGenericUnixKeychain) {
361
+ error.actions = [messages.getMessage('macKeychainOutOfSync')];
362
+ }
363
+ throw error;
364
+ }
365
+ });
366
+ }
231
367
  async getKeyChain(platform) {
232
368
  if (!this.options.keychain) {
233
369
  this.options.keychain = await (0, keyChain_1.retrieveKeychain)(platform);
@@ -12,7 +12,7 @@ const logger_1 = require("../logger/logger");
12
12
  const messages_1 = require("../messages");
13
13
  const keyChainImpl_1 = require("./keyChainImpl");
14
14
  ;
15
- const messages = new messages_1.Messages('@salesforce/core', 'encryption', new Map([["invalidEncryptedFormatError", "The encrypted data is not properly formatted."], ["invalidEncryptedFormatError.actions", ["If attempting to create a scratch org then re-authorize. Otherwise create a new scratch org."]], ["authDecryptError", "Failed to decipher auth data. reason: %s."], ["unsupportedOperatingSystemError", "Unsupported Operating System: %s"], ["missingCredentialProgramError", "Unable to find required security software: %s"], ["credentialProgramAccessError", "Unable to execute security software: %s"], ["passwordRetryError", "Failed to get the password after %i retries."], ["passwordRequiredError", "A password is required."], ["keyChainServiceRequiredError", "Unable to get or set a keychain value without a service name."], ["keyChainAccountRequiredError", "Unable to get or set a keychain value without an account name."], ["keyChainUserCanceledError", "User canceled authentication."], ["keychainPasswordCreationError", "Failed to create a password in the keychain."], ["genericKeychainServiceError", "The service and account specified in %s do not match the version of the toolbelt."], ["genericKeychainServiceError.actions", ["Check your toolbelt version and re-auth."]], ["genericKeychainInvalidPermsError", "Invalid file permissions for secret file"], ["genericKeychainInvalidPermsError.actions", ["Ensure the file %s has the file permission octal value of %s."]], ["passwordNotFoundError", "Could not find password.\n%s"], ["passwordNotFoundError.actions", ["Ensure a valid password is returned with the following command: [%s]"]], ["setCredentialError", "Command failed with response:\n%s"], ["setCredentialError.actions", ["Determine why this command failed to set an encryption key for user %s: [%s]."]], ["macKeychainOutOfSync", "We\u2019ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands."]]));
15
+ const messages = new messages_1.Messages('@salesforce/core', 'encryption', new Map([["invalidEncryptedFormatError", "The encrypted data is not properly formatted."], ["invalidEncryptedFormatError.actions", ["If attempting to create a scratch org then re-authorize. Otherwise create a new scratch org."]], ["authDecryptError", "Failed to decipher auth data. reason: %s."], ["unsupportedOperatingSystemError", "Unsupported Operating System: %s"], ["missingCredentialProgramError", "Unable to find required security software: %s"], ["credentialProgramAccessError", "Unable to execute security software: %s"], ["passwordRetryError", "Failed to get the password after %i retries."], ["passwordRequiredError", "A password is required."], ["keyChainServiceRequiredError", "Unable to get or set a keychain value without a service name."], ["keyChainAccountRequiredError", "Unable to get or set a keychain value without an account name."], ["keyChainUserCanceledError", "User canceled authentication."], ["keychainPasswordCreationError", "Failed to create a password in the keychain."], ["genericKeychainServiceError", "The service and account specified in %s do not match the version of the toolbelt."], ["genericKeychainServiceError.actions", ["Check your toolbelt version and re-auth."]], ["genericKeychainInvalidPermsError", "Invalid file permissions for secret file"], ["genericKeychainInvalidPermsError.actions", ["Ensure the file %s has the file permission octal value of %s."]], ["passwordNotFoundError", "Could not find password.\n%s"], ["passwordNotFoundError.actions", ["Ensure a valid password is returned with the following command: [%s]"]], ["setCredentialError", "Command failed with response:\n%s"], ["setCredentialError.actions", ["Determine why this command failed to set an encryption key for user %s: [%s]."]], ["macKeychainOutOfSync", "We\u2019ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands."], ["v1CryptoWithV2KeyWarning", "The SF_CRYPTO_V2 environment variable was set to \"false\" but a v2 crypto key was detected. v1 crypto can only be used with a v1 key. Unset the SF_CRYPTO_V2 environment variable."], ["v2CryptoWithV1KeyWarning", "SF_CRYPTO_V2 was set to \"true\" but a v1 crypto key was detected. v2 crypto can only be used with a v2 key. To generate a v2 key:\n\n1. Logout of all orgs: `sf org logout --all`\n2. Delete the sfdx keychain entry (account: local, service: sfdx). If `SF_USE_GENERIC_UNIX_KEYCHAIN=true` env var is set, you can delete the `key.json` file.\n3. Set `SF_CRYPTO_V2=true` env var.\n4. Re-Authenticate with your orgs using the CLI org login commands."]]));
16
16
  /**
17
17
  * Gets the os level keychain impl.
18
18
  *
@@ -41,7 +41,7 @@ const kit_1 = require("@salesforce/kit");
41
41
  const global_1 = require("../global");
42
42
  const messages_1 = require("../messages");
43
43
  ;
44
- const messages = new messages_1.Messages('@salesforce/core', 'encryption', new Map([["invalidEncryptedFormatError", "The encrypted data is not properly formatted."], ["invalidEncryptedFormatError.actions", ["If attempting to create a scratch org then re-authorize. Otherwise create a new scratch org."]], ["authDecryptError", "Failed to decipher auth data. reason: %s."], ["unsupportedOperatingSystemError", "Unsupported Operating System: %s"], ["missingCredentialProgramError", "Unable to find required security software: %s"], ["credentialProgramAccessError", "Unable to execute security software: %s"], ["passwordRetryError", "Failed to get the password after %i retries."], ["passwordRequiredError", "A password is required."], ["keyChainServiceRequiredError", "Unable to get or set a keychain value without a service name."], ["keyChainAccountRequiredError", "Unable to get or set a keychain value without an account name."], ["keyChainUserCanceledError", "User canceled authentication."], ["keychainPasswordCreationError", "Failed to create a password in the keychain."], ["genericKeychainServiceError", "The service and account specified in %s do not match the version of the toolbelt."], ["genericKeychainServiceError.actions", ["Check your toolbelt version and re-auth."]], ["genericKeychainInvalidPermsError", "Invalid file permissions for secret file"], ["genericKeychainInvalidPermsError.actions", ["Ensure the file %s has the file permission octal value of %s."]], ["passwordNotFoundError", "Could not find password.\n%s"], ["passwordNotFoundError.actions", ["Ensure a valid password is returned with the following command: [%s]"]], ["setCredentialError", "Command failed with response:\n%s"], ["setCredentialError.actions", ["Determine why this command failed to set an encryption key for user %s: [%s]."]], ["macKeychainOutOfSync", "We\u2019ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands."]]));
44
+ const messages = new messages_1.Messages('@salesforce/core', 'encryption', new Map([["invalidEncryptedFormatError", "The encrypted data is not properly formatted."], ["invalidEncryptedFormatError.actions", ["If attempting to create a scratch org then re-authorize. Otherwise create a new scratch org."]], ["authDecryptError", "Failed to decipher auth data. reason: %s."], ["unsupportedOperatingSystemError", "Unsupported Operating System: %s"], ["missingCredentialProgramError", "Unable to find required security software: %s"], ["credentialProgramAccessError", "Unable to execute security software: %s"], ["passwordRetryError", "Failed to get the password after %i retries."], ["passwordRequiredError", "A password is required."], ["keyChainServiceRequiredError", "Unable to get or set a keychain value without a service name."], ["keyChainAccountRequiredError", "Unable to get or set a keychain value without an account name."], ["keyChainUserCanceledError", "User canceled authentication."], ["keychainPasswordCreationError", "Failed to create a password in the keychain."], ["genericKeychainServiceError", "The service and account specified in %s do not match the version of the toolbelt."], ["genericKeychainServiceError.actions", ["Check your toolbelt version and re-auth."]], ["genericKeychainInvalidPermsError", "Invalid file permissions for secret file"], ["genericKeychainInvalidPermsError.actions", ["Ensure the file %s has the file permission octal value of %s."]], ["passwordNotFoundError", "Could not find password.\n%s"], ["passwordNotFoundError.actions", ["Ensure a valid password is returned with the following command: [%s]"]], ["setCredentialError", "Command failed with response:\n%s"], ["setCredentialError.actions", ["Determine why this command failed to set an encryption key for user %s: [%s]."]], ["macKeychainOutOfSync", "We\u2019ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands."], ["v1CryptoWithV2KeyWarning", "The SF_CRYPTO_V2 environment variable was set to \"false\" but a v2 crypto key was detected. v1 crypto can only be used with a v1 key. Unset the SF_CRYPTO_V2 environment variable."], ["v2CryptoWithV1KeyWarning", "SF_CRYPTO_V2 was set to \"true\" but a v1 crypto key was detected. v2 crypto can only be used with a v2 key. To generate a v2 key:\n\n1. Logout of all orgs: `sf org logout --all`\n2. Delete the sfdx keychain entry (account: local, service: sfdx). If `SF_USE_GENERIC_UNIX_KEYCHAIN=true` env var is set, you can delete the `key.json` file.\n3. Set `SF_CRYPTO_V2=true` env var.\n4. Re-Authenticate with your orgs using the CLI org login commands."]]));
45
45
  const GET_PASSWORD_RETRY_COUNT = 3;
46
46
  /**
47
47
  * Helper to reduce an array of cli args down to a presentable string for logging.
package/lib/exported.d.ts CHANGED
@@ -20,7 +20,7 @@ export { SfdcUrl } from './util/sfdcUrl';
20
20
  export { getJwtAudienceUrl } from './util/getJwtAudienceUrl';
21
21
  export { Fields, FieldValue, LoggerLevel, LoggerLevelValue, LogLine, LoggerOptions, Logger } from './logger/logger';
22
22
  export { Messages, StructuredMessage } from './messages';
23
- export { Org, SandboxProcessObject, StatusEvent, SandboxEvents, SandboxUserAuthResponse, SandboxUserAuthRequest, SandboxRequest, ResumeSandboxRequest, OrgTypes, ResultEvent, ScratchOrgRequest, } from './org/org';
23
+ export { Org, SandboxProcessObject, StatusEvent, SandboxInfo, SandboxEvents, SandboxUserAuthResponse, SandboxUserAuthRequest, SandboxRequest, ResumeSandboxRequest, OrgTypes, ResultEvent, ScratchOrgRequest, } from './org/org';
24
24
  export { OrgConfigProperties, ORG_CONFIG_ALLOWED_PROPERTIES } from './org/orgConfigProperties';
25
25
  export { PackageDir, NamedPackageDir, PackageDirDependency, SfProject, SfProjectJson } from './sfProject';
26
26
  export { SchemaValidator } from './schema/validator';
package/lib/org/org.d.ts CHANGED
@@ -71,6 +71,24 @@ export type ResumeSandboxRequest = {
71
71
  SandboxName?: string;
72
72
  SandboxProcessObjId?: string;
73
73
  };
74
+ export type SandboxInfo = {
75
+ Id: string;
76
+ IsDeleted: boolean;
77
+ CreatedDate: string;
78
+ CreatedById: string;
79
+ LastModifiedDate: string;
80
+ LastModifiedById: string;
81
+ SandboxName: string;
82
+ LicenseType: 'DEVELOPER' | 'DEVELOPER PRO' | 'PARTIAL' | 'FULL';
83
+ TemplateId?: string;
84
+ HistoryDays: -1 | 0 | 10 | 20 | 30 | 60 | 90 | 120 | 150 | 180;
85
+ CopyChatter: boolean;
86
+ AutoActivate: boolean;
87
+ ApexClassId?: string;
88
+ Description?: string;
89
+ SourceId?: string;
90
+ CopyArchivedActivities?: boolean;
91
+ };
74
92
  export type ScratchOrgRequest = Omit<ScratchOrgCreateOptions, 'hubOrg'>;
75
93
  export type SandboxFields = {
76
94
  sandboxOrgId: string;
@@ -130,6 +148,18 @@ export declare class Org extends AsyncOptionalCreatable<Org.Options> {
130
148
  interval?: Duration;
131
149
  async?: boolean;
132
150
  }): Promise<SandboxProcessObject>;
151
+ /**
152
+ * Refresh (update) a sandbox from a production org.
153
+ * 'this' needs to be a production org with sandbox licenses available
154
+ *
155
+ * @param sandboxInfo SandboxInfo to update the sandbox with
156
+ * @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
157
+ */
158
+ refreshSandbox(sandboxInfo: SandboxInfo, options?: {
159
+ wait?: Duration;
160
+ interval?: Duration;
161
+ async?: boolean;
162
+ }): Promise<SandboxProcessObject>;
133
163
  /**
134
164
  *
135
165
  * @param sandboxReq SandboxRequest options to create the sandbox with
@@ -142,10 +172,10 @@ export declare class Org extends AsyncOptionalCreatable<Org.Options> {
142
172
  interval?: Duration;
143
173
  }): Promise<SandboxProcessObject>;
144
174
  /**
145
- * Resume a sandbox creation from a production org.
175
+ * Resume a sandbox create or refresh from a production org.
146
176
  * `this` needs to be a production org with sandbox licenses available.
147
177
  *
148
- * @param resumeSandboxRequest SandboxRequest options to create the sandbox with
178
+ * @param resumeSandboxRequest SandboxRequest options to create/refresh the sandbox with
149
179
  * @param options Wait: The amount of time to wait (default: 0 minutes) before timing out,
150
180
  * Interval: The time interval (default: 30 seconds) between polling
151
181
  */
package/lib/org/org.js CHANGED
@@ -52,7 +52,7 @@ const authInfo_1 = require("./authInfo");
52
52
  const scratchOrgCreate_1 = require("./scratchOrgCreate");
53
53
  const orgConfigProperties_1 = require("./orgConfigProperties");
54
54
  ;
55
- const messages = new messages_1.Messages('@salesforce/core', 'org', new Map([["notADevHub", "The provided dev hub username %s is not a valid dev hub."], ["noUsernameFound", "No username found."], ["noDevHubFound", "Unable to associate this scratch org with a DevHub."], ["deleteOrgHubError", "The Dev Hub org cannot be deleted."], ["insufficientAccessToDelete", "You do not have the appropriate permissions to delete a scratch org. Please contact your Salesforce admin."], ["scratchOrgNotFound", "Attempting to delete an expired or deleted org"], ["sandboxDeleteFailed", "The sandbox org deletion failed with a result of %s."], ["sandboxNotFound", "We can't find a SandboxProcess for the sandbox %s."], ["sandboxInfoCreateFailed", "The sandbox org creation failed with a result of %s."], ["missingAuthUsername", "The sandbox %s does not have an authorized username."], ["orgPollingTimeout", "Sandbox status is %s; timed out waiting for completion."], ["NotFoundOnDevHub", "The scratch org does not belong to the dev hub username %s."], ["AuthInfoOrgIdUndefined", "AuthInfo orgId is undefined."], ["sandboxCreateNotComplete", "The sandbox creation has not completed."], ["SandboxProcessNotFoundBySandboxName", "We can't find a SandboxProcess with the SandboxName %s."], ["MultiSandboxProcessNotFoundBySandboxName", "We found more than one SandboxProcess with the SandboxName %s."], ["sandboxNotResumable", "The sandbox %s cannot resume with status of %s."]]));
55
+ const messages = new messages_1.Messages('@salesforce/core', 'org', new Map([["notADevHub", "The provided dev hub username %s is not a valid dev hub."], ["noUsernameFound", "No username found."], ["noDevHubFound", "Unable to associate this scratch org with a DevHub."], ["deleteOrgHubError", "The Dev Hub org cannot be deleted."], ["insufficientAccessToDelete", "You do not have the appropriate permissions to delete a scratch org. Please contact your Salesforce admin."], ["scratchOrgNotFound", "Attempting to delete an expired or deleted org"], ["sandboxDeleteFailed", "The sandbox org deletion failed with a result of %s."], ["sandboxNotFound", "We can't find a SandboxProcess for the sandbox %s."], ["sandboxInfoCreateFailed", "The sandbox org creation failed with a result of %s."], ["sandboxInfoRefreshFailed", "The sandbox org refresh failed with a result of %s."], ["missingAuthUsername", "The sandbox %s does not have an authorized username."], ["orgPollingTimeout", "Sandbox status is %s; timed out waiting for completion."], ["NotFoundOnDevHub", "The scratch org does not belong to the dev hub username %s."], ["AuthInfoOrgIdUndefined", "AuthInfo orgId is undefined."], ["sandboxCreateNotComplete", "The sandbox creation has not completed."], ["SandboxProcessNotFoundBySandboxName", "We can't find a SandboxProcess with the SandboxName %s."], ["MultiSandboxProcessNotFoundBySandboxName", "We found more than one SandboxProcess with the SandboxName %s."], ["sandboxNotResumable", "The sandbox %s cannot resume with status of %s."]]));
56
56
  var OrgTypes;
57
57
  (function (OrgTypes) {
58
58
  OrgTypes["Scratch"] = "scratch";
@@ -72,6 +72,19 @@ function sandboxIsResumable(value) {
72
72
  return resumableSandboxStatus.includes(value);
73
73
  }
74
74
  exports.sandboxIsResumable = sandboxIsResumable;
75
+ const sandboxProcessFields = [
76
+ 'Id',
77
+ 'Status',
78
+ 'SandboxName',
79
+ 'SandboxInfoId',
80
+ 'LicenseType',
81
+ 'CreatedDate',
82
+ 'CopyProgress',
83
+ 'SandboxOrganization',
84
+ 'SourceId',
85
+ 'Description',
86
+ 'EndDate',
87
+ ];
75
88
  /**
76
89
  * Provides a way to manage a locally authenticated Org.
77
90
  *
@@ -141,6 +154,46 @@ class Org extends kit_1.AsyncOptionalCreatable {
141
154
  pollInterval,
142
155
  });
143
156
  }
157
+ /**
158
+ * Refresh (update) a sandbox from a production org.
159
+ * 'this' needs to be a production org with sandbox licenses available
160
+ *
161
+ * @param sandboxInfo SandboxInfo to update the sandbox with
162
+ * @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
163
+ */
164
+ async refreshSandbox(sandboxInfo, options = {
165
+ wait: kit_1.Duration.minutes(6),
166
+ async: false,
167
+ interval: kit_1.Duration.seconds(30),
168
+ }) {
169
+ this.logger.debug(sandboxInfo, 'RefreshSandbox called with SandboxInfo');
170
+ const refreshResult = await this.connection.tooling.update('SandboxInfo', sandboxInfo);
171
+ this.logger.debug(refreshResult, 'Return from calling tooling.update');
172
+ if (!refreshResult.success) {
173
+ throw messages.createError('sandboxInfoRefreshFailed', [JSON.stringify(refreshResult)]);
174
+ }
175
+ const soql = `SELECT ${sandboxProcessFields.join(',')} FROM SandboxProcess WHERE SandboxName='${sandboxInfo.SandboxName}' ORDER BY CreatedDate DESC`;
176
+ const sbxProcessObjects = (await this.connection.tooling.query(soql)).records.filter((item) => !item.Status.startsWith('Del'));
177
+ this.logger.debug(sbxProcessObjects, `SandboxProcesses for ${sandboxInfo.SandboxName}`);
178
+ // throw if none found
179
+ if (sbxProcessObjects?.length === 0) {
180
+ throw new Error(`No SandboxProcesses found for: ${sandboxInfo.SandboxName}`);
181
+ }
182
+ const sandboxRefreshProgress = sbxProcessObjects[0];
183
+ const isAsync = !!options.async;
184
+ if (isAsync) {
185
+ // The user didn't want us to poll, so simply return the status
186
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxRefreshProgress);
187
+ return sandboxRefreshProgress;
188
+ }
189
+ const [wait, pollInterval] = this.validateWaitOptions(options);
190
+ this.logger.debug(sandboxRefreshProgress, `refresh - pollStatusAndAuth sandboxProcessObj, max wait time of ${wait.minutes} minutes`);
191
+ return this.pollStatusAndAuth({
192
+ sandboxProcessObj: sandboxRefreshProgress,
193
+ wait,
194
+ pollInterval,
195
+ });
196
+ }
144
197
  /**
145
198
  *
146
199
  * @param sandboxReq SandboxRequest options to create the sandbox with
@@ -154,10 +207,10 @@ class Org extends kit_1.AsyncOptionalCreatable {
154
207
  return this.createSandbox(sandboxReq, options);
155
208
  }
156
209
  /**
157
- * Resume a sandbox creation from a production org.
210
+ * Resume a sandbox create or refresh from a production org.
158
211
  * `this` needs to be a production org with sandbox licenses available.
159
212
  *
160
- * @param resumeSandboxRequest SandboxRequest options to create the sandbox with
213
+ * @param resumeSandboxRequest SandboxRequest options to create/refresh the sandbox with
161
214
  * @param options Wait: The amount of time to wait (default: 0 minutes) before timing out,
162
215
  * Interval: The time interval (default: 30 seconds) between polling
163
216
  */
@@ -861,7 +914,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
861
914
  async queryLatestSandboxProcessBySandboxName(sandboxNameIn) {
862
915
  const { tooling } = this.getConnection();
863
916
  this.logger.debug(`QueryLatestSandboxProcessBySandboxName called with SandboxName: ${sandboxNameIn}`);
864
- const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE SandboxName='${sandboxNameIn}' AND Status != 'D' ORDER BY CreatedDate DESC LIMIT 1`;
917
+ const queryStr = `SELECT ${sandboxProcessFields.join(',')} FROM SandboxProcess WHERE SandboxName='${sandboxNameIn}' AND Status != 'D' ORDER BY CreatedDate DESC LIMIT 1`;
865
918
  const queryResult = await tooling.query(queryStr);
866
919
  this.logger.debug(queryResult, 'Return from calling queryToolingApi');
867
920
  if (queryResult?.records?.length === 1) {
@@ -1071,6 +1124,17 @@ class Org extends kit_1.AsyncOptionalCreatable {
1071
1124
  oauth2Options.privateKey = productionAuthFields.privateKey;
1072
1125
  oauth2Options.clientId = productionAuthFields.clientId;
1073
1126
  }
1127
+ // Before creating the AuthInfo, delete any existing auth files for the sandbox.
1128
+ // This is common when refreshing sandboxes, and will cause AuthInfo to throw
1129
+ // because it doesn't want to overwrite existing auth files.
1130
+ const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
1131
+ try {
1132
+ await stateAggregator.orgs.read(sandboxRes.authUserName);
1133
+ await stateAggregator.orgs.remove(sandboxRes.authUserName);
1134
+ }
1135
+ catch (e) {
1136
+ // ignore since this is only for deleting existing auth files.
1137
+ }
1074
1138
  const authInfo = await authInfo_1.AuthInfo.create({
1075
1139
  username: sandboxRes.authUserName,
1076
1140
  oauth2Options,
@@ -1081,8 +1145,11 @@ class Org extends kit_1.AsyncOptionalCreatable {
1081
1145
  productionAuthFieldsUsername: productionAuthFields.username,
1082
1146
  ...oauth2Options,
1083
1147
  }, 'Creating AuthInfo for sandbox');
1084
- // save auth info for new sandbox
1085
- await authInfo.save();
1148
+ // save auth info for sandbox
1149
+ await authInfo.save({
1150
+ isScratch: false,
1151
+ isSandbox: true,
1152
+ });
1086
1153
  const sandboxOrgId = authInfo.getFields().orgId;
1087
1154
  if (!sandboxOrgId) {
1088
1155
  throw messages.createError('AuthInfoOrgIdUndefined');
@@ -1157,7 +1224,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
1157
1224
  * @private
1158
1225
  */
1159
1226
  async querySandboxProcess(where) {
1160
- const soql = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE ${where} ORDER BY CreatedDate DESC`;
1227
+ const soql = `SELECT ${sandboxProcessFields.join(',')} FROM SandboxProcess WHERE ${where} ORDER BY CreatedDate DESC`;
1161
1228
  const result = (await this.connection.tooling.query(soql)).records.filter((item) => !item.Status.startsWith('Del'));
1162
1229
  if (result.length === 0) {
1163
1230
  throw new sfError_1.SfError(`No record found for ${soql}`, connection_1.SingleRecordQueryErrors.NoRecords);
@@ -1204,15 +1271,15 @@ class Org extends kit_1.AsyncOptionalCreatable {
1204
1271
  return result;
1205
1272
  }
1206
1273
  catch (err) {
1207
- const error = err;
1274
+ const error = err instanceof Error ? err : sfError_1.SfError.wrap((0, ts_types_1.isString)(err) ? err : 'unknown');
1208
1275
  // There are cases where the endDate is set before the sandbox has actually completed.
1209
1276
  // In that case, the sandboxAuth call will throw a specific exception.
1210
1277
  if (error?.name === 'INVALID_STATUS') {
1211
- this.logger.debug('Error while authenticating the user', error?.toString());
1278
+ this.logger.debug('Error while authenticating the user:', error.message);
1212
1279
  }
1213
1280
  else {
1214
- // If it fails for any unexpected reason, just pass that through
1215
- throw sfError_1.SfError.wrap(error);
1281
+ // If it fails for any unexpected reason, rethrow
1282
+ throw error;
1216
1283
  }
1217
1284
  }
1218
1285
  }
@@ -83,3 +83,16 @@ Command failed with response:
83
83
  # macKeychainOutOfSync
84
84
 
85
85
  We’ve encountered an error with the Mac keychain being out of sync with your `sfdx` credentials. To fix the problem, sync your credentials by authenticating into your org again using the auth commands.
86
+
87
+ # v1CryptoWithV2KeyWarning
88
+
89
+ The SF_CRYPTO_V2 environment variable was set to "false" but a v2 crypto key was detected. v1 crypto can only be used with a v1 key. Unset the SF_CRYPTO_V2 environment variable.
90
+
91
+ # v2CryptoWithV1KeyWarning
92
+
93
+ SF_CRYPTO_V2 was set to "true" but a v1 crypto key was detected. v2 crypto can only be used with a v2 key. To generate a v2 key:
94
+
95
+ 1. Logout of all orgs: `sf org logout --all`
96
+ 2. Delete the sfdx keychain entry (account: local, service: sfdx). If `SF_USE_GENERIC_UNIX_KEYCHAIN=true` env var is set, you can delete the `key.json` file.
97
+ 3. Set `SF_CRYPTO_V2=true` env var.
98
+ 4. Re-Authenticate with your orgs using the CLI org login commands.
package/messages/org.md CHANGED
@@ -34,6 +34,10 @@ We can't find a SandboxProcess for the sandbox %s.
34
34
 
35
35
  The sandbox org creation failed with a result of %s.
36
36
 
37
+ # sandboxInfoRefreshFailed
38
+
39
+ The sandbox org refresh failed with a result of %s.
40
+
37
41
  # missingAuthUsername
38
42
 
39
43
  The sandbox %s does not have an authorized username.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/core",
3
- "version": "6.5.6",
3
+ "version": "6.7.0",
4
4
  "description": "Core libraries to interact with SFDX projects, orgs, and APIs.",
5
5
  "main": "lib/exported",
6
6
  "types": "lib/exported.d.ts",