Skip to content

Commit

Permalink
chore: lint fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
shetzel committed Jan 31, 2024
1 parent b9b947c commit aaa7aad
Showing 1 changed file with 209 additions and 143 deletions.
352 changes: 209 additions & 143 deletions test/unit/crypto/cryptoTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,178 +14,244 @@ import { SfError } from '../../../src/sfError';
import { Messages } from '../../../src/messages';
import { TestContext, shouldThrowSync } from '../../../src/testSetup';

const TEST_KEY = {
const TEST_KEY_V1 = {
service: 'sfdx',
account: 'local',
key: '8e8fd1e6dc06a37bf420898dbc3ee35c',
};

describe('CryptoTest', function () {
const TEST_KEY_V2 = {
service: 'sfdx',
account: 'local',
key: 'f699321865468a386434e78b3a4a5cf3b151e09a4391741e06fdbe8272ac07c0',
};

const setCryptoVersionEnvVar = (envVarValue?: boolean) => {
if (envVarValue === true) {
process.env.SF_CRYPTO_V2 = 'true';
} else if (envVarValue === false) {
process.env.SF_CRYPTO_V2 = 'false';
} else {
delete process.env.SF_CRYPTO_V2;
}
};

describe('CryptoTests', function () {
// Save env var original state
const disableEncryptionEnvVar = process.env.SFDX_DISABLE_ENCRYPTION;
const cryptoVersionEnvVar = process.env.SF_CRYPTO_V2;
let crypto: Crypto;

const $$ = new TestContext();

beforeEach(() => {
// Testing crypto functionality, so restore global stubs.
$$.SANDBOXES.CRYPTO.restore();

stubMethod($$.SANDBOX, Crypto.prototype, 'getKeyChain').callsFake(() =>
Promise.resolve({
setPassword: () => Promise.resolve(),
getPassword: (data: unknown, cb: (arg1: undefined, arg2: string) => {}) => cb(undefined, TEST_KEY.key),
})
);
});

afterEach(() => {
crypto.close();
process.env.SFDX_DISABLE_ENCRYPTION = disableEncryptionEnvVar ?? '';
});

if (process.platform === 'darwin') {
this.timeout(3 * 60 * 1000);
after(() => {
// Reset env vars to original state
if (disableEncryptionEnvVar) {
process.env.SFDX_DISABLE_ENCRYPTION = disableEncryptionEnvVar;
} else {
delete process.env.SFDX_DISABLE_ENCRYPTION;
}

if (cryptoVersionEnvVar) {
process.env.SF_CRYPTO_V2 = cryptoVersionEnvVar;
} else {
delete process.env.SF_CRYPTO_V2;
}
});

const runTests = ({ keyVersion, envVarValue }: { keyVersion: 'v1' | 'v2'; envVarValue?: boolean }) => {
if (process.platform === 'darwin') {
this.timeout(3 * 60 * 1000);

const text = 'Unencrypted text';
let secret: string | undefined;
const text = 'Unencrypted text';
let secret: string | undefined;

it('Should have encrypted the string.', async () => {
process.env.SFDX_DISABLE_ENCRYPTION = 'false';
const key = keyVersion === 'v2' ? TEST_KEY_V2.key : TEST_KEY_V1.key;

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
secret = crypto.encrypt(text);
expect(secret).to.not.equal(text);
});
beforeEach(() => {
stubMethod($$.SANDBOX, Crypto.prototype, 'getKeyChain').callsFake(() =>
Promise.resolve({
setPassword: () => Promise.resolve(),
getPassword: (data: unknown, cb: (arg1: undefined, arg2: string) => {}) => cb(undefined, key),
})
);
stubMethod($$.SANDBOX, Crypto.prototype, 'getCryptoVersion').returns(envVarValue ? 'v2' : 'v1');
});

it('Should have decrypted the string', async () => {
process.env.SFDX_DISABLE_ENCRYPTION = 'false';
it('Should have encrypted the string.', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SFDX_DISABLE_ENCRYPTION = 'false';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
if (!secret) throw new Error('secret is undefined');
const decrypted = crypto.decrypt(secret);
expect(decrypted).to.equal(text);
});
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
secret = crypto.encrypt(text);
expect(secret).to.not.equal(text);
});

it('Should have encrypted the string even if SFDX_DISABLE_ENCRYPTION is true.', async () => {
process.env.SFDX_DISABLE_ENCRYPTION = 'true';
it('Should have decrypted the string', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SFDX_DISABLE_ENCRYPTION = 'false';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
secret = crypto.encrypt(text);
expect(secret).to.not.equal(text);
});
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
if (!secret) throw new Error('secret is undefined');
const decrypted = crypto.decrypt(secret);
expect(decrypted).to.equal(text);
});

it('Should have encrypted the string because SFDX_DISABLE_ENCRYPTION is not defined.', async () => {
delete process.env.SFDX_DISABLE_ENCRYPTION;
it('Should have encrypted the string even if SFDX_DISABLE_ENCRYPTION is true.', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SFDX_DISABLE_ENCRYPTION = 'true';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
secret = crypto.encrypt(text);
expect(secret).to.not.equal(text);
});

it('Should have decrypted the string even if SFDX_DISABLE_ENCRYPTION is "true"', async () => {
process.env.SFDX_DISABLE_ENCRYPTION = 'true';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
const str = '123456';
const encrypted = crypto.encrypt(str);
const decrypted = crypto.decrypt(encrypted);
expect(encrypted).to.not.equal(str);
expect(decrypted).to.equal(str);
});

it('InvalidEncryptedFormatError action', async () => {
process.env.SFDX_DISABLE_ENCRYPTION = 'false';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
expect(Crypto.prototype.decrypt.bind(crypto, 'foo')).to.throw(Error).and.have.property('actions');
});

it('InvalidEncryptedFormatError name', async () => {
process.env.SFDX_DISABLE_ENCRYPTION = 'false';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
expect(Crypto.prototype.decrypt.bind(crypto, ''))
.to.throw(Error)
.and.have.property('name', 'InvalidEncryptedFormatError');
});

it('Should return null if text is null.', async () => {
delete process.env.SFDX_DISABLE_ENCRYPTION;
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
secret = crypto.encrypt(text);
expect(secret).to.not.equal(text);
});

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
// @ts-expect-error -> null cannot be assigned to string
secret = crypto.encrypt(null);
expect(secret).to.equal(undefined);
});
it('Should have encrypted the string because SFDX_DISABLE_ENCRYPTION is not defined.', async () => {
setCryptoVersionEnvVar(envVarValue);
delete process.env.SFDX_DISABLE_ENCRYPTION;

it('Should return null if text is undefined.', async () => {
delete process.env.SFDX_DISABLE_ENCRYPTION;
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
secret = crypto.encrypt(text);
expect(secret).to.not.equal(text);
});

crypto = new Crypto();
// @ts-expect-error: access protected method
await crypto.init();
// @ts-expect-error: falsy value
secret = crypto.encrypt(undefined);
expect(secret).to.equal(undefined);
});

it('Decrypt should fail without env var, and add extra message', async () => {
const message = Messages.loadMessages('@salesforce/core', 'encryption').getMessage('macKeychainOutOfSync');
const err = Error('Failed to decipher auth data. reason: Unsupported state or unable to authenticate data.');
const sfdxErr = SfError.wrap(err);
sfdxErr.actions = [];
sfdxErr.actions[0] = message;
stubMethod($$.SANDBOX, os, 'platform').returns('darwin');
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
$$.SANDBOX.stub(crypto, 'decrypt').throws(sfdxErr);
expect(() => crypto.decrypt('abcdefghijklmnopqrstuvwxyz:123456789')).to.throw(
'Failed to decipher auth data. reason: Unsupported state or unable to authenticate data.'
);
try {
shouldThrowSync(() => crypto.decrypt('abcdefghijklmnopqrstuvwxyz:123456789'));
} catch (error) {
const sfError = error as SfError;
if (!sfError.actions) throw new Error('sfError.actions is undefined');
expect(sfError.actions[0]).to.equal(message);
}
});

it('Decrypt should fail but not add extra message with env var', async () => {
process.env.SF_USE_GENERIC_UNIX_KEYCHAIN = 'false';
const message: string = Messages.loadMessages('@salesforce/core', 'encryption').getMessage('authDecryptError');
const errorMessage: object = SfError.wrap(new Error(message));
stubMethod($$.SANDBOX, os, 'platform').returns('darwin');
stubMethod($$.SANDBOX, crypto, 'decrypt').callsFake(() => ({
setAuthTag: () => {
throw errorMessage;
},
update: () => {},
final: () => {},
}));
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
// @ts-expect-error: secret is not a string
expect(() => crypto.decrypt(secret)).to.not.throw(message);
delete process.env.SF_USE_GENERIC_UNIX_KEYCHAIN;
});
}
it('Should have decrypted the string even if SFDX_DISABLE_ENCRYPTION is "true"', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SFDX_DISABLE_ENCRYPTION = 'true';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
const str = '123456';
const encrypted = crypto.encrypt(str);
const decrypted = crypto.decrypt(encrypted);
expect(encrypted).to.not.equal(str);
expect(decrypted).to.equal(str);
});

it('InvalidEncryptedFormatError action', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SFDX_DISABLE_ENCRYPTION = 'false';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
expect(Crypto.prototype.decrypt.bind(crypto, 'foo')).to.throw(Error).and.have.property('actions');
});

it('InvalidEncryptedFormatError name', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SFDX_DISABLE_ENCRYPTION = 'false';

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
expect(Crypto.prototype.decrypt.bind(crypto, ''))
.to.throw(Error)
.and.have.property('name', 'InvalidEncryptedFormatError');
});

it('Should return null if text is null.', async () => {
setCryptoVersionEnvVar(envVarValue);
delete process.env.SFDX_DISABLE_ENCRYPTION;

crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
// @ts-expect-error -> null cannot be assigned to string
secret = crypto.encrypt(null);
expect(secret).to.equal(undefined);
});

it('Should return null if text is undefined.', async () => {
setCryptoVersionEnvVar(envVarValue);
delete process.env.SFDX_DISABLE_ENCRYPTION;

crypto = new Crypto();
// @ts-expect-error: access protected method
await crypto.init();
// @ts-expect-error: falsy value
secret = crypto.encrypt(undefined);
expect(secret).to.equal(undefined);
});

it('Decrypt should fail without env var, and add extra message', async () => {
setCryptoVersionEnvVar(envVarValue);
const message = Messages.loadMessages('@salesforce/core', 'encryption').getMessage('macKeychainOutOfSync');
const err = Error('Failed to decipher auth data. reason: Unsupported state or unable to authenticate data.');
const sfdxErr = SfError.wrap(err);
sfdxErr.actions = [];
sfdxErr.actions[0] = message;
stubMethod($$.SANDBOX, os, 'platform').returns('darwin');
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
$$.SANDBOX.stub(crypto, 'decrypt').throws(sfdxErr);
expect(() => crypto.decrypt('abcdefghijklmnopqrstuvwxyz:123456789')).to.throw(
'Failed to decipher auth data. reason: Unsupported state or unable to authenticate data.'
);
try {
shouldThrowSync(() => crypto.decrypt('abcdefghijklmnopqrstuvwxyz:123456789'));
} catch (error) {
const sfError = error as SfError;
if (!sfError.actions) throw new Error('sfError.actions is undefined');
expect(sfError.actions[0]).to.equal(message);
}
});

it('Decrypt should fail but not add extra message with env var', async () => {
setCryptoVersionEnvVar(envVarValue);
process.env.SF_USE_GENERIC_UNIX_KEYCHAIN = 'false';
const message: string = Messages.loadMessages('@salesforce/core', 'encryption').getMessage('authDecryptError');
const errorMessage: object = SfError.wrap(new Error(message));
stubMethod($$.SANDBOX, os, 'platform').returns('darwin');
stubMethod($$.SANDBOX, crypto, 'decrypt').callsFake(() => ({
setAuthTag: () => {
throw errorMessage;
},
update: () => {},
final: () => {},
}));
crypto = new Crypto();
// @ts-expect-error -> init is protected
await crypto.init();
// @ts-expect-error: secret is not a string
expect(() => crypto.decrypt(secret)).to.not.throw(message);
delete process.env.SF_USE_GENERIC_UNIX_KEYCHAIN;
});
}
};

describe('v1 crypto with v1 key, without env var', () => {
runTests({ keyVersion: 'v1' });
});

describe('v1 crypto with v1 key, with env var', () => {
runTests({ keyVersion: 'v1', envVarValue: false });
});

describe('v2 crypto with v1 key', () => {
runTests({ keyVersion: 'v1', envVarValue: true });
});

describe('v2 crypto with v2 key', () => {
runTests({ keyVersion: 'v2', envVarValue: true });
});
});

2 comments on commit aaa7aad

@svc-cli-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger Benchmarks - ubuntu-latest

Benchmark suite Current: aaa7aad Previous: b9b947c Ratio
Child logger creation 476865 ops/sec (±2.14%) 480040 ops/sec (±1.01%) 1.01
Logging a string on root logger 852529 ops/sec (±7.47%) 749811 ops/sec (±6.65%) 0.88
Logging an object on root logger 585079 ops/sec (±5.09%) 593063 ops/sec (±11.03%) 1.01
Logging an object with a message on root logger 7812 ops/sec (±204.25%) 10537 ops/sec (±201.06%) 1.35
Logging an object with a redacted prop on root logger 411029 ops/sec (±13.06%) 498451 ops/sec (±8.01%) 1.21
Logging a nested 3-level object on root logger 354011 ops/sec (±7.38%) 339647 ops/sec (±8.76%) 0.96

This comment was automatically generated by workflow using github-action-benchmark.

@svc-cli-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger Benchmarks - windows-latest

Benchmark suite Current: aaa7aad Previous: b9b947c Ratio
Child logger creation 315736 ops/sec (±1.47%) 322956 ops/sec (±0.85%) 1.02
Logging a string on root logger 715035 ops/sec (±10.74%) 753656 ops/sec (±5.53%) 1.05
Logging an object on root logger 569940 ops/sec (±6.72%) 536006 ops/sec (±6.53%) 0.94
Logging an object with a message on root logger 11081 ops/sec (±189.50%) 12238 ops/sec (±188.95%) 1.10
Logging an object with a redacted prop on root logger 402242 ops/sec (±13.90%) 414243 ops/sec (±31.86%) 1.03
Logging a nested 3-level object on root logger 321498 ops/sec (±4.91%) 353535 ops/sec (±5.47%) 1.10

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.