UNPKG

@salesforce/core

Version:

Core libraries to interact with SFDX projects, orgs, and APIs.

210 lines 8.73 kB
"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 = void 0; exports.getLoginAudienceCombos = getLoginAudienceCombos; const node_url_1 = require("node: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/logger"); const lifecycleEvents_1 = require("../lifecycleEvents"); const envVars_1 = require("../config/envVars"); 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 node_url_1.URL(login); const a = new node_url_1.URL(audience); acc.set(`${l.origin}:${a.origin}`, [login, audience]); return acc; }, new Map()); return [...reduced.values()]; } class SfdcUrl extends node_url_1.URL { /** * Salesforce URLs */ static SANDBOX = 'https://test.salesforce.com'; static PRODUCTION = 'https://login.salesforce.com'; static cache = new Set(); logger; envVars; 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}`); } this.envVars = new envVars_1.EnvVars(); } static isValidUrl(input) { try { new node_url_1.URL(input.toString()); return true; } catch { return false; } } /** * Returns the appropriate jwt audience url for this url * Use SF_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 = this.envVars.getString('SF_AUDIENCE_URL', ''); if (envVarVal) { this.logger.debug(`Audience URL overridden by env var SF_AUDIENCE_URL=${envVarVal}`); return envVarVal; } if (Boolean(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', '.sfcrmproducts.cn', ]; const allowlistOfSalesforceHosts = ['developer.salesforce.com', 'trailhead.salesforce.com']; return allowlistOfSalesforceDomainPatterns.some((pattern) => 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', '.crm.dev', // workspaces container ]; 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'); } // CN Specific domains for Alibaba Cloud if (this.origin.endsWith('.my.sfcrmproducts.cn')) { return this.origin.replace('.my.sfcrmproducts.cn', '.lightning.sfcrmapps.cn'); } // 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 SF_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)(this.envVars.getNumber('SF_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 node_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 SF_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)(this.envVars.getNumber('SF_DOMAIN_RETRY', 240)); const timeout = new kit_1.Duration(quantity, kit_1.Duration.Unit.SECONDS); const resolver = await myDomainResolver_1.MyDomainResolver.create({ url: new node_url_1.URL(this.origin), timeout, frequency: new kit_1.Duration(1, kit_1.Duration.Unit.SECONDS), }); return resolver.resolve(); } /** * Test whether this url represents a lightning domain * * @returns {boolean} true if this domain is a lightning domain */ isLightningDomain() { return (this.origin.includes('.lightning.force.com') || this.origin.includes('.lightning.crmforce.mil') || this.origin.includes('.lightning.sfcrmapps.cn')); } } exports.SfdcUrl = SfdcUrl; //# sourceMappingURL=sfdcUrl.js.map