@salesforce/core
Version:
Core libraries to interact with SFDX projects, orgs, and APIs.
218 lines • 9.52 kB
JavaScript
"use strict";
/*
* Copyright (c) 2021, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SfdcUrl = exports.getLoginAudienceCombos = void 0;
const url_1 = require("url");
const kit_1 = require("@salesforce/kit");
const ts_types_1 = require("@salesforce/ts-types");
const myDomainResolver_1 = require("../status/myDomainResolver");
const logger_1 = require("../logger");
const lifecycleEvents_1 = require("../lifecycleEvents");
function getLoginAudienceCombos(audienceUrl, loginUrl) {
const filtered = [
[loginUrl, loginUrl],
[SfdcUrl.SANDBOX, SfdcUrl.SANDBOX],
[SfdcUrl.PRODUCTION, SfdcUrl.PRODUCTION],
[audienceUrl, audienceUrl],
[audienceUrl, SfdcUrl.PRODUCTION],
[audienceUrl, SfdcUrl.SANDBOX],
[loginUrl, audienceUrl],
[loginUrl, SfdcUrl.PRODUCTION],
[loginUrl, SfdcUrl.SANDBOX],
[SfdcUrl.PRODUCTION, audienceUrl],
[SfdcUrl.SANDBOX, audienceUrl],
].filter(([login, audience]) => !((login === SfdcUrl.PRODUCTION && audience === SfdcUrl.SANDBOX) ||
(login === SfdcUrl.SANDBOX && audience === SfdcUrl.PRODUCTION)));
const reduced = filtered.reduce((acc, [login, audience]) => {
const l = new url_1.URL(login);
const a = new url_1.URL(audience);
acc.set(`${l.origin}:${a.origin}`, [login, audience]);
return acc;
}, new Map());
return [...reduced.values()];
}
exports.getLoginAudienceCombos = getLoginAudienceCombos;
class SfdcUrl extends url_1.URL {
constructor(input, base) {
super(input.toString(), base);
if (this.protocol !== 'https:' && !SfdcUrl.cache.has(this.origin)) {
SfdcUrl.cache.add(this.origin);
void lifecycleEvents_1.Lifecycle.getInstance().emitWarning(`Using insecure protocol: ${this.protocol} on url: ${this.origin}`);
}
}
static isValidUrl(input) {
try {
new url_1.URL(input.toString());
return true;
}
catch {
return false;
}
}
/**
* Returns the appropriate jwt audience url for this url
* Use SFDX_AUDIENCE_URL env var to override the audience url
*
* @param createdOrgInstance The Salesforce instance the org was created on. e.g. `cs42`
* @return {Promise<string>} The audience url
*/
async getJwtAudienceUrl(createdOrgInstance) {
this.logger = await logger_1.Logger.child('SfdcUrl');
// environment variable is used as an override
const envVarVal = new kit_1.Env().getString('SFDX_AUDIENCE_URL', '');
if (envVarVal) {
this.logger.debug(`Audience URL overridden by env var SFDX_AUDIENCE_URL=${envVarVal}`);
return envVarVal;
}
if ((createdOrgInstance && /^gs1/gi.test(createdOrgInstance)) || /(gs1.my.salesforce.com)/gi.test(this.origin)) {
return 'https://gs1.salesforce.com';
}
return SfdcUrl.PRODUCTION;
}
/**
* Tests whether this url contains a Salesforce owned domain
*
* @return {boolean} true if this is a salesforce domain
*/
isSalesforceDomain() {
// Source https://help.salesforce.com/articleView?id=000003652&type=1
const allowlistOfSalesforceDomainPatterns = [
'.cloudforce.com',
'.content.force.com',
'.force.com',
'.salesforce.com',
'.salesforceliveagent.com',
'.secure.force.com',
'crmforce.mil',
];
const allowlistOfSalesforceHosts = ['developer.salesforce.com', 'trailhead.salesforce.com'];
return allowlistOfSalesforceDomainPatterns.some((pattern) => {
return this.hostname.endsWith(pattern) || allowlistOfSalesforceHosts.includes(this.hostname);
});
}
/**
* Tests whether this url is an internal Salesforce domain
*
* @returns {boolean} true if this is an internal domain
*/
isInternalUrl() {
const INTERNAL_URL_PARTS = [
'.vpod.',
'stm.salesforce.com',
'stm.force.com',
'.blitz.salesforce.com',
'.stm.salesforce.ms',
'.pc-rnd.force.com',
'.pc-rnd.salesforce.com',
];
return (this.origin.startsWith('https://gs1.') ||
this.isLocalUrl() ||
INTERNAL_URL_PARTS.some((part) => this.origin.includes(part)));
}
/**
* Tests whether this url runs on a local machine
*
* @returns {boolean} true if this is a local machine
*/
isLocalUrl() {
const LOCAL_PARTS = ['localhost.sfdcdev.', '.internal.'];
return LOCAL_PARTS.some((part) => this.origin.includes(part));
}
toLightningDomain() {
if (this.origin.endsWith('.my.salesforce.mil')) {
return this.origin.replace('.my.salesforce.mil', '.lightning.crmforce.mil');
}
// enhanced domains
// ex: sandbox.my.salesforce.com, scratch.my.salesforce.com, etc
if (this.origin.endsWith('.my.salesforce.com')) {
return this.origin.replace('.my.salesforce.com', '.lightning.force.com');
}
// alternative domains
if (this.origin.endsWith('.my-salesforce.com')) {
return this.origin.replace('.my-salesforce.com', '.my-lightning.com');
}
// all non-mil domains
return `https://${(0, ts_types_1.ensureArray)(/https?:\/\/([^.]*)/.exec(this.origin))
.slice(1, 2)
.pop()}.lightning.force.com`;
}
/**
* Tests whether this url has the lightning domain extension
* This method that performs the dns lookup of the host. If the lookup fails the internal polling (1 second), client will try again until timeout
* If SFDX_DOMAIN_RETRY environment variable is set (number) it overrides the default timeout duration (240 seconds)
*
* @returns {Promise<true | never>} The resolved ip address or never
* @throws {@link SfError} If can't resolve DNS.
*/
async checkLightningDomain() {
const quantity = (0, ts_types_1.ensureNumber)(new kit_1.Env().getNumber('SFDX_DOMAIN_RETRY', 240));
const timeout = new kit_1.Duration(quantity, kit_1.Duration.Unit.SECONDS);
if (this.isInternalUrl() || timeout.seconds === 0) {
return true;
}
const resolver = await myDomainResolver_1.MyDomainResolver.create({
url: new url_1.URL(this.toLightningDomain()),
timeout,
frequency: new kit_1.Duration(1, kit_1.Duration.Unit.SECONDS),
});
await resolver.resolve();
return true;
}
/**
* Method that performs the dns lookup of the host. If the lookup fails the internal polling (1 second), client will try again until timeout
* If SFDX_DOMAIN_RETRY environment variable is set (number) it overrides the default timeout duration (240 seconds)
*
* @returns the resolved ip address.
* @throws {@link SfError} If can't resolve DNS.
*/
async lookup() {
const quantity = (0, ts_types_1.ensureNumber)(new kit_1.Env().getNumber('SFDX_DOMAIN_RETRY', 240));
const timeout = new kit_1.Duration(quantity, kit_1.Duration.Unit.SECONDS);
const resolver = await myDomainResolver_1.MyDomainResolver.create({
url: new url_1.URL(this.origin),
timeout,
frequency: new kit_1.Duration(1, kit_1.Duration.Unit.SECONDS),
});
return resolver.resolve();
}
/**
* Tests whether this url is a sandbox url
*
* @Deprecated - identification of a sandbox instance by URL alone is not deterministic
* @param createdOrgInstance The Salesforce instance the org was created on. e.g. `cs42`
* @returns {boolean}
*/
// TODO: how to get rid of this?
isSandboxUrl(createdOrgInstance) {
return ((createdOrgInstance && /^cs|s$/gi.test(createdOrgInstance)) ||
this.origin.endsWith('sandbox.my.salesforce.mil') ||
/sandbox\.my\.salesforce\.com/gi.test(this.origin) || // enhanced domains >= 230
/(cs[0-9]+(\.my|)\.salesforce\.com)/gi.test(this.origin) || // my domains on CS instance OR CS instance without my domain
/(cs[0-9]+\.force\.com)/gi.test(this.origin) || // sandboxes have cnames like cs123.force.com
/(\w+--\w+\.my\.salesforce\.com)/gi.test(this.origin) || // sandboxes myDomain like foo--bar.my.salesforce.com
/([a-z]{3}[0-9]+s\.sfdc-.+\.salesforce\.com)/gi.test(this.origin) || // falcon sandbox ex: usa2s.sfdc-whatever.salesforce.com
/([a-z]{3}[0-9]+s\.sfdc-.+\.force\.com)/gi.test(this.origin) || // falcon sandbox ex: usa2s.sfdc-whatever.force.com
this.hostname === 'test.salesforce.com');
}
/**
* Test whether this url represents a lightning domain
*
* @returns {boolean} true if this domain is a lightning domain
*/
isLightningDomain() {
return /\.lightning\.force\.com/.test(this.origin) || /\.lightning\.crmforce\.mil/.test(this.origin);
}
}
exports.SfdcUrl = SfdcUrl;
/**
* Salesforce URLs
*/
SfdcUrl.SANDBOX = 'https://test.salesforce.com';
SfdcUrl.PRODUCTION = 'https://login.salesforce.com';
SfdcUrl.cache = new Set();
//# sourceMappingURL=sfdcUrl.js.map