Skip to content

Commit

Permalink
feat: sfdxAuthUrl support port in instanceUrl
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Nov 13, 2024
1 parent a471d1e commit b82e1da
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 43 deletions.
18 changes: 7 additions & 11 deletions src/org/authInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ export class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
sfdxAuthUrl: string
): Pick<AuthFields, 'clientId' | 'clientSecret' | 'refreshToken' | 'loginUrl'> {
const match = sfdxAuthUrl.match(
/^force:\/\/([a-zA-Z0-9._-]+={0,2}):([a-zA-Z0-9._-]*={0,2}):([a-zA-Z0-9._-]+={0,2})@([a-zA-Z0-9._-]+)/
/^force:\/\/([a-zA-Z0-9._-]+={0,2}):([a-zA-Z0-9._-]*={0,2}):([a-zA-Z0-9._-]+={0,2})@([a-zA-Z0-9:._-]+)/
);

if (!match) {
Expand Down Expand Up @@ -687,16 +687,12 @@ export class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
* **See** [SFDX Authorization](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_auth.htm#cli_reference_force_auth)
*/
public getSfdxAuthUrl(): string {
const decryptedFields = this.getFields(true);
const instanceUrl = ensure(decryptedFields.instanceUrl, 'undefined instanceUrl').replace(/^https?:\/\//, '');
let sfdxAuthUrl = 'force://';

if (decryptedFields.clientId) {
sfdxAuthUrl += `${decryptedFields.clientId}:${decryptedFields.clientSecret ?? ''}:`;
}

sfdxAuthUrl += `${ensure(decryptedFields.refreshToken, 'undefined refreshToken')}@${instanceUrl}`;
return sfdxAuthUrl;
const { clientId, clientSecret, refreshToken, instanceUrl } = this.getFields(true);
// host includes an optional port on the instanceUrl
const url = new URL(ensure(instanceUrl, 'undefined instanceUrl')).host;
const clientIdAndSecret = clientId ? `${clientId}:${clientSecret ?? ''}` : '';
const token = ensure(refreshToken, 'undefined refreshToken');
return `force://${clientIdAndSecret}:${token}@${url}`;
}

/**
Expand Down
125 changes: 93 additions & 32 deletions test/unit/org/authInfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import jwt from 'jsonwebtoken';
import { env, includes } from '@salesforce/kit';
import { spyMethod, stubMethod } from '@salesforce/ts-sinon';
import { AnyJson, getJsonMap, JsonMap, toJsonMap } from '@salesforce/ts-types';
import { expect } from 'chai';
import { expect, config as chaiConfig } from 'chai';
import { Transport } from '@jsforce/jsforce-node/lib/transport';

import { OAuth2 } from '@jsforce/jsforce-node';
Expand All @@ -34,6 +34,7 @@ import { SfdcUrl } from '../../../src/util/sfdcUrl';
import * as suggestion from '../../../src/util/findSuggestion';
import { SfError } from '../../../src';

chaiConfig.truncateThreshold = 0;
class AuthInfoMockOrg extends MockTestOrgData {
public privateKey = 'authInfoTest/jwt/server.key';
public expirationDate = '12-02-20';
Expand Down Expand Up @@ -1273,13 +1274,15 @@ describe('AuthInfo', () => {
);
});

it('should handle undefined client secret', async () => {
it('should handle instance url with a port on it', async () => {
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();

const url = new URL(`${testOrg.instanceUrl}:6101`);

const authResponse = {
access_token: testOrg.accessToken,
instance_url: testOrg.instanceUrl,
instance_url: url.toString(),
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
};

Expand All @@ -1291,17 +1294,17 @@ describe('AuthInfo', () => {
username: testOrg.username,
oauth2Options: {
refreshToken: testOrg.refreshToken,
loginUrl: testOrg.loginUrl,
loginUrl: url.toString(),
},
});

// delete the client secret
authInfo.update({ clientSecret: undefined });
const instanceUrl = testOrg.instanceUrl.replace('https://', '');
expect(authInfo.getSfdxAuthUrl()).to.contain(`force://PlatformCLI::${testOrg.refreshToken}@${instanceUrl}`);
// host will include the port
const result = authInfo.getSfdxAuthUrl();
expect(result).to.contain(url.port);
expect(result).to.contain(url.host);
});

it('should handle undefined refresh token', async () => {
it('should handle undefined client secret', async () => {
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();

Expand All @@ -1323,37 +1326,67 @@ describe('AuthInfo', () => {
},
});

// delete the refresh token
authInfo.update({ ...authInfo.getFields(), refreshToken: undefined });
expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined refreshToken');
// delete the client secret
authInfo.update({ clientSecret: undefined });
const instanceUrl = testOrg.instanceUrl.replace('https://', '');
expect(authInfo.getSfdxAuthUrl()).to.contain(`force://PlatformCLI::${testOrg.refreshToken}@${instanceUrl}`);
});

it('should handle undefined instance url', async () => {
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();
describe('error conditions', () => {
it('should handle undefined refresh token', async () => {
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();

const authResponse = {
access_token: testOrg.accessToken,
instance_url: testOrg.instanceUrl,
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
};
const authResponse = {
access_token: testOrg.accessToken,
instance_url: testOrg.instanceUrl,
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
};

// Stub the http request (OAuth2.refreshToken())
postParamsStub.resolves(authResponse);
// Stub the http request (OAuth2.refreshToken())
postParamsStub.resolves(authResponse);

// Create the refresh token AuthInfo instance
const authInfo = await AuthInfo.create({
username: testOrg.username,
oauth2Options: {
refreshToken: testOrg.refreshToken,
loginUrl: testOrg.loginUrl,
},
// Create the refresh token AuthInfo instance
const authInfo = await AuthInfo.create({
username: testOrg.username,
oauth2Options: {
refreshToken: testOrg.refreshToken,
loginUrl: testOrg.loginUrl,
},
});

// delete the refresh token
authInfo.update({ ...authInfo.getFields(), refreshToken: undefined });
expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined refreshToken');
});

// delete the instance url
authInfo.update({ ...authInfo.getFields(), instanceUrl: undefined });
it('should handle undefined instance url', async () => {
stubMethod($$.SANDBOX, AuthInfo.prototype, 'determineIfDevHub').resolves(false);
stubMethod($$.SANDBOX, AuthInfo.prototype, 'getNamespacePrefix').resolves();

expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined instanceUrl');
const authResponse = {
access_token: testOrg.accessToken,
instance_url: testOrg.instanceUrl,
id: '00DAuthInfoTest_orgId/005AuthInfoTest_userId',
};

// Stub the http request (OAuth2.refreshToken())
postParamsStub.resolves(authResponse);

// Create the refresh token AuthInfo instance
const authInfo = await AuthInfo.create({
username: testOrg.username,
oauth2Options: {
refreshToken: testOrg.refreshToken,
loginUrl: testOrg.loginUrl,
},
});

// delete the instance url
authInfo.update({ ...authInfo.getFields(), instanceUrl: undefined });

expect(() => authInfo.getSfdxAuthUrl()).to.throw('undefined instanceUrl');
});
});
});

Expand Down Expand Up @@ -1703,6 +1736,19 @@ describe('AuthInfo', () => {
expect(options.loginUrl).to.equal('https://test.my.salesforce.com');
});

it('should parse the correct url with a port on the end', () => {
const options = AuthInfo.parseSfdxAuthUrl(
'force://PlatformCLI::5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYUB.@test.my.salesforce.com:6101'
);

expect(options.refreshToken).to.equal(
'5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYUB.'
);
expect(options.clientId).to.equal('PlatformCLI');
expect(options.clientSecret).to.equal('');
expect(options.loginUrl).to.equal('https://test.my.salesforce.com:6101');
});

it('should parse an id, secret, and token that include = for padding', () => {
const options = AuthInfo.parseSfdxAuthUrl(
'force://3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o=:438437816653243682==:5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYU==@test.my.salesforce.com'
Expand All @@ -1718,6 +1764,21 @@ describe('AuthInfo', () => {
expect(options.loginUrl).to.equal('https://test.my.salesforce.com');
});

it('should parse an id, secret, and token that include = for padding and a port', () => {
const options = AuthInfo.parseSfdxAuthUrl(
'force://3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o=:438437816653243682==:5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYU==@test.my.salesforce.com:6101'
);

expect(options.refreshToken).to.equal(
'5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYU=='
);
expect(options.clientId).to.equal(
'3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o='
);
expect(options.clientSecret).to.equal('438437816653243682==');
expect(options.loginUrl).to.equal('https://test.my.salesforce.com:6101');
});

it('should parse the correct url with client secret', () => {
const options = AuthInfo.parseSfdxAuthUrl(
'force://3MVG9SemV5D80oBfPBCgboxuJ9cOMLWNM1DDOZ8zgvJGsz13H3J66coUBCFF3N0zEgLYijlkqeWk4ot_Q2.4o:438437816653243682:5Aep861_OKMvio5gy8xCNsXxybPdupY9fVEZyeVOvb4kpOZx5Z1QLB7k7n5flEqEWKcwUQEX1I.O5DCFwjlYUB.@test.my.salesforce.com'
Expand Down

4 comments on commit b82e1da

@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: b82e1da Previous: b62073c Ratio
Child logger creation 513245 ops/sec (±2.12%) 472153 ops/sec (±1.05%) 0.92
Logging a string on root logger 962333 ops/sec (±10.47%) 818053 ops/sec (±6.42%) 0.85
Logging an object on root logger 41466 ops/sec (±185.96%) 616196 ops/sec (±7.84%) 14.86
Logging an object with a message on root logger 491403 ops/sec (±9.30%) 4215 ops/sec (±220.08%) 0.008577481211958412
Logging an object with a redacted prop on root logger 630438 ops/sec (±5.35%) 452439 ops/sec (±7.56%) 0.72
Logging a nested 3-level object on root logger 11332 ops/sec (±208.57%) 379982 ops/sec (±7.57%) 33.53

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.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Logger Benchmarks - ubuntu-latest'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: b82e1da Previous: b62073c Ratio
Logging an object on root logger 41466 ops/sec (±185.96%) 616196 ops/sec (±7.84%) 14.86
Logging a nested 3-level object on root logger 11332 ops/sec (±208.57%) 379982 ops/sec (±7.57%) 33.53

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: b82e1da Previous: b62073c Ratio
Child logger creation 354904 ops/sec (±0.52%) 327284 ops/sec (±1.00%) 0.92
Logging a string on root logger 835732 ops/sec (±10.70%) 822428 ops/sec (±7.09%) 0.98
Logging an object on root logger 696516 ops/sec (±10.48%) 645143 ops/sec (±7.84%) 0.93
Logging an object with a message on root logger 27552 ops/sec (±183.70%) 20136 ops/sec (±185.44%) 0.73
Logging an object with a redacted prop on root logger 546246 ops/sec (±8.23%) 459493 ops/sec (±7.69%) 0.84
Logging a nested 3-level object on root logger 18017 ops/sec (±188.70%) 329164 ops/sec (±6.88%) 18.27

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.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Logger Benchmarks - windows-latest'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: b82e1da Previous: b62073c Ratio
Logging a nested 3-level object on root logger 18017 ops/sec (±188.70%) 329164 ops/sec (±6.88%) 18.27

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

Please sign in to comment.