From 50b0e7e53333a974e90840415a424b11f96da6e7 Mon Sep 17 00:00:00 2001 From: Nicolas Kruk Date: Tue, 17 Sep 2024 01:50:18 -0400 Subject: [PATCH 1/7] fix: authentication --- package.json | 1 + src/commands/lightning/dev/site.ts | 5 +- src/shared/experience/expSite.ts | 135 +++++++++++++++++++++++++++++ yarn.lock | 19 ++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e98b3b02..cfc63db0 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@salesforce/sf-plugins-core": "^11.2.4", "@inquirer/select": "^2.4.7", "@inquirer/prompts": "^5.3.8", + "axios": "^1.7.7", "chalk": "^5.3.0", "lwc": "7.1.3", "lwr": "0.14.2", diff --git a/src/commands/lightning/dev/site.ts b/src/commands/lightning/dev/site.ts index d3e31114..5e0e931d 100644 --- a/src/commands/lightning/dev/site.ts +++ b/src/commands/lightning/dev/site.ts @@ -67,9 +67,12 @@ export default class LightningDevSite extends SfCommand { // Pass the org auth token so LWR can make authenticated requests to core const authToken = org.getConnection().accessToken ?? ''; + const networkId = await selectedSite.getNetworkIdByName(); + const sidToken = await selectedSite.getNewSidToken(networkId); + // Start the dev server await expDev({ - authToken, + authToken: sidToken || authToken, open: true, port: 3000, logLevel: 'error', diff --git a/src/shared/experience/expSite.ts b/src/shared/experience/expSite.ts index 38ea2b5a..b85c831d 100644 --- a/src/shared/experience/expSite.ts +++ b/src/shared/experience/expSite.ts @@ -7,6 +7,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { Org, SfError } from '@salesforce/core'; +import axios from 'axios'; export type SiteMetadata = { bundleName: string; @@ -225,6 +226,140 @@ export class ExperienceSite { return resourcePath; } + + // TODO cleanup + public async getNetworkIdByName(): Promise { + const conn = this.org.getConnection(); + // try { + // Query the Network object for the network with the given site name + const result = await conn.query<{ Id: string }>(`SELECT Id FROM Network WHERE Name = '${this.siteDisplayName}'`); + + const record = result.records[0]; + if (record) { + let networkId = record.Id; + // Subtract the last three characters from the Network ID + networkId = networkId.substring(0, networkId.length - 3); + return networkId; + } else { + throw new Error(`Network with name '${this.siteDisplayName}' not found`); + } + // } catch (error) { + // // console.error('Error fetching Network ID:', error); + // throw error; + // } + } + + public async getNewSidToken(networkId: string): Promise { + // Get the connection and access token from the org + const conn = this.org.getConnection(); + const identity = await conn.identity(); + if (identity.user_id) { + // do something + } + const orgId = this.org.getOrgId(); + const orgIdMinus3 = orgId.substring(0, orgId.length - 3); + const accessToken = conn.accessToken; + const instanceUrl = conn.instanceUrl; + + // Construct the switch URL + const switchUrl = `${instanceUrl}/servlet/networks/switch?networkId=${networkId}`; + + // try { + // Make the GET request without following redirects + if (accessToken) { + const cookies = [ + `sid=${accessToken}`, + `oid=${orgIdMinus3}`, + // 'sid_Client=s000000uuCPw000000I7xV', + // Include other essential cookies if necessary + // For example: + // `oid=${conn.getAuthInfoFields().orgId}`, + // `sid_Client=${conn.userInfo.id}`, + // Add any other cookies that might be required + ] + .join('; ') + .trim(); + let response = await axios.get(switchUrl, { + headers: { + Cookie: cookies, + // Include other headers if necessary + // 'User-Agent': 'Your User Agent String', + // 'Referer': 'Referer URL if required', + }, + withCredentials: true, + maxRedirects: 0, // Prevent axios from following redirects + validateStatus: (status) => status >= 200 && status < 400, // Accept 3xx status codes + }); + + // Extract the Location header + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const locationHeader = response.headers['location']; + + if (locationHeader) { + // Parse the URL to extract the 'sid' parameter + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const urlObj = new URL(locationHeader); + const sid = urlObj.searchParams.get('sid') ?? ''; + const cookies2 = [ + '__Secure-has-sid=1', + `sid=${sid}`, + `oid=${orgIdMinus3}`, + // 'sid_Client=s000000uuCPw000000I7xV', + // Include other essential cookies if necessary + // For example: + // `oid=${conn.getAuthInfoFields().orgId}`, + // `sid_Client=${conn.userInfo.id}`, + // Add any other cookies that might be required + ] + .join('; ') + .trim(); + + response = await axios.get(urlObj.toString(), { + headers: { + Cookie: cookies2, + // Include other headers if necessary + // 'User-Agent': 'Your User Agent String', + // 'Referer': 'Referer URL if required', + }, + withCredentials: true, + maxRedirects: 0, // Prevent axios from following redirects + validateStatus: (status) => status >= 200 && status < 400, // Accept 3xx status codes + }); + const setCookieHeader = response.headers['set-cookie']; + if (setCookieHeader) { + // 'set-cookie' can be an array if multiple cookies are set + // Find the 'sid' cookie in the set-cookie header + const sidCookie = setCookieHeader.find((cookieStr: string) => cookieStr.startsWith('sid=')); + + if (sidCookie) { + // Extract the sid value from the cookie string + const sidMatch = sidCookie.match(/sid=([^;]+)/); + if (sidMatch?.[1]) { + const sidToken = sidMatch[1]; + return sidToken; + } + } + } else { + // eslint-disable-next-line no-console + console.log('error couldnt find set-cookie header for sid token'); + } + + if (sid) { + return sid; + } else { + throw new Error('SID token not found in Location header'); + } + } else { + throw new Error('Location header not found in response'); + } + } + return ''; + // } catch (error) { + // // Handle errors (e.g., network issues, HTTP errors) + // // console.error('Error obtaining new SID token:', error); + // throw error; + // } + } } /** diff --git a/yarn.lock b/yarn.lock index d3ef1d7e..5948f185 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6126,6 +6126,15 @@ axe-core@^4.6.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59" integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g== +axios@^1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^3.1.1: version "3.2.4" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.4.tgz#6dfba930294ea14d7d2fc68b9d007211baedb94c" @@ -8695,6 +8704,11 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -12991,6 +13005,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" From 8bc6f108e77e92ff04c66923964fe0b540e808c6 Mon Sep 17 00:00:00 2001 From: Nicolas Kruk Date: Tue, 17 Sep 2024 19:54:01 -0400 Subject: [PATCH 2/7] chore: cleanup code --- src/commands/lightning/dev/site.ts | 9 +-- src/shared/experience/expSite.ts | 107 +++++++++++------------------ 2 files changed, 45 insertions(+), 71 deletions(-) diff --git a/src/commands/lightning/dev/site.ts b/src/commands/lightning/dev/site.ts index 5e0e931d..a41d4eab 100644 --- a/src/commands/lightning/dev/site.ts +++ b/src/commands/lightning/dev/site.ts @@ -64,15 +64,12 @@ export default class LightningDevSite extends SfCommand { } } - // Pass the org auth token so LWR can make authenticated requests to core - const authToken = org.getConnection().accessToken ?? ''; - - const networkId = await selectedSite.getNetworkIdByName(); - const sidToken = await selectedSite.getNewSidToken(networkId); + // Establish a valid access token for this site + const authToken = await selectedSite.setupAuth(); // Start the dev server await expDev({ - authToken: sidToken || authToken, + authToken, open: true, port: 3000, logLevel: 'error', diff --git a/src/shared/experience/expSite.ts b/src/shared/experience/expSite.ts index b85c831d..3750142d 100644 --- a/src/shared/experience/expSite.ts +++ b/src/shared/experience/expSite.ts @@ -95,6 +95,26 @@ export class ExperienceSite { return experienceSites; } + /** + * Steps to init: + * 1) Verify the site is an actual site within this organization + * 2) Verify and output specific message if wrong site type is selected + * 2) Verify that site has been published with Local Dev perm enabled (i.e. a static resource exists for this site name) + * 3) Establish sid token for proxied requests + */ + // public async init(): Promise {} + + /** + * Esablish a valid token for this local development session + * + * @returns sid token for proxied site requests + */ + public async setupAuth(): Promise { + const networkId = await this.getNetworkId(); + const sidToken = await this.getNewSidToken(networkId); + return sidToken; + } + public async isUpdateAvailable(): Promise { const localMetadata = this.getLocalMetadata(); if (!localMetadata) { @@ -227,10 +247,8 @@ export class ExperienceSite { return resourcePath; } - // TODO cleanup - public async getNetworkIdByName(): Promise { + public async getNetworkId(): Promise { const conn = this.org.getConnection(); - // try { // Query the Network object for the network with the given site name const result = await conn.query<{ Id: string }>(`SELECT Id FROM Network WHERE Name = '${this.siteDisplayName}'`); @@ -243,48 +261,30 @@ export class ExperienceSite { } else { throw new Error(`Network with name '${this.siteDisplayName}' not found`); } - // } catch (error) { - // // console.error('Error fetching Network ID:', error); - // throw error; - // } } public async getNewSidToken(networkId: string): Promise { // Get the connection and access token from the org const conn = this.org.getConnection(); - const identity = await conn.identity(); - if (identity.user_id) { - // do something - } const orgId = this.org.getOrgId(); + + // Not sure if we need to do this const orgIdMinus3 = orgId.substring(0, orgId.length - 3); - const accessToken = conn.accessToken; - const instanceUrl = conn.instanceUrl; + const accessToken = conn.accessToken; // TODO should we be refreshing before use? + const instanceUrl = conn.instanceUrl; // Org URL - // Construct the switch URL + // Call out to the servlet to establish a session const switchUrl = `${instanceUrl}/servlet/networks/switch?networkId=${networkId}`; - // try { // Make the GET request without following redirects if (accessToken) { - const cookies = [ - `sid=${accessToken}`, - `oid=${orgIdMinus3}`, - // 'sid_Client=s000000uuCPw000000I7xV', - // Include other essential cookies if necessary - // For example: - // `oid=${conn.getAuthInfoFields().orgId}`, - // `sid_Client=${conn.userInfo.id}`, - // Add any other cookies that might be required - ] - .join('; ') - .trim(); + // TODO should we always refreshAuth? + // await conn.refreshAuth(); + + const cookies = [`sid=${accessToken}`, `oid=${orgIdMinus3}`].join('; ').trim(); let response = await axios.get(switchUrl, { headers: { Cookie: cookies, - // Include other headers if necessary - // 'User-Agent': 'Your User Agent String', - // 'Referer': 'Referer URL if required', }, withCredentials: true, maxRedirects: 0, // Prevent axios from following redirects @@ -294,32 +294,15 @@ export class ExperienceSite { // Extract the Location header // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const locationHeader = response.headers['location']; - if (locationHeader) { // Parse the URL to extract the 'sid' parameter // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const urlObj = new URL(locationHeader); const sid = urlObj.searchParams.get('sid') ?? ''; - const cookies2 = [ - '__Secure-has-sid=1', - `sid=${sid}`, - `oid=${orgIdMinus3}`, - // 'sid_Client=s000000uuCPw000000I7xV', - // Include other essential cookies if necessary - // For example: - // `oid=${conn.getAuthInfoFields().orgId}`, - // `sid_Client=${conn.userInfo.id}`, - // Add any other cookies that might be required - ] - .join('; ') - .trim(); - + const cookies2 = ['__Secure-has-sid=1', `sid=${sid}`, `oid=${orgIdMinus3}`].join('; ').trim(); response = await axios.get(urlObj.toString(), { headers: { Cookie: cookies2, - // Include other headers if necessary - // 'User-Agent': 'Your User Agent String', - // 'Referer': 'Referer URL if required', }, withCredentials: true, maxRedirects: 0, // Prevent axios from following redirects @@ -330,7 +313,6 @@ export class ExperienceSite { // 'set-cookie' can be an array if multiple cookies are set // Find the 'sid' cookie in the set-cookie header const sidCookie = setCookieHeader.find((cookieStr: string) => cookieStr.startsWith('sid=')); - if (sidCookie) { // Extract the sid value from the cookie string const sidMatch = sidCookie.match(/sid=([^;]+)/); @@ -339,26 +321,21 @@ export class ExperienceSite { return sidToken; } } - } else { - // eslint-disable-next-line no-console - console.log('error couldnt find set-cookie header for sid token'); - } - - if (sid) { - return sid; - } else { - throw new Error('SID token not found in Location header'); } - } else { - throw new Error('Location header not found in response'); } + // eslint-disable-next-line no-console + console.warn( + `Warning: could not establish valid auth token for your site '${this.siteDisplayName}'.` + + 'Local Dev proxied requests to your site may fail or return data from the guest user context.' + ); + + return accessToken; } + // eslint-disable-next-line no-console + console.warn( + 'Warning: sf cli org connection missing accessToken. Local Dev proxied requests to your site may fail or return data from the guest user context.' + ); return ''; - // } catch (error) { - // // Handle errors (e.g., network issues, HTTP errors) - // // console.error('Error obtaining new SID token:', error); - // throw error; - // } } } From 73dd25c06794f0cc6d4d6354f6b6cb95dd46c11d Mon Sep 17 00:00:00 2001 From: Nicolas Kruk Date: Tue, 17 Sep 2024 20:44:44 -0400 Subject: [PATCH 3/7] chore: cleanup --- src/shared/experience/expSite.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/shared/experience/expSite.ts b/src/shared/experience/expSite.ts index 3750142d..d5789292 100644 --- a/src/shared/experience/expSite.ts +++ b/src/shared/experience/expSite.ts @@ -95,15 +95,6 @@ export class ExperienceSite { return experienceSites; } - /** - * Steps to init: - * 1) Verify the site is an actual site within this organization - * 2) Verify and output specific message if wrong site type is selected - * 2) Verify that site has been published with Local Dev perm enabled (i.e. a static resource exists for this site name) - * 3) Establish sid token for proxied requests - */ - // public async init(): Promise {} - /** * Esablish a valid token for this local development session * From 6f96a7da91576ec2fd4a41c4b5412ca35b51c5a3 Mon Sep 17 00:00:00 2001 From: svc-cli-bot Date: Wed, 18 Sep 2024 00:47:38 +0000 Subject: [PATCH 4/7] chore(release): 1.2.1-alpha.0 [skip ci] --- README.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 624f27e9..47bc14ec 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ EXAMPLES $ sf lightning dev app --target-org myOrg --device-type ios --device-id "iPhone 15 Pro Max" ``` -_See code: [src/commands/lightning/dev/app.ts](https://github.com/salesforcecli/plugin-lightning-dev/blob/1.2.0/src/commands/lightning/dev/app.ts)_ +_See code: [src/commands/lightning/dev/app.ts](https://github.com/salesforcecli/plugin-lightning-dev/blob/1.2.1-alpha.0/src/commands/lightning/dev/app.ts)_ ## `sf lightning dev site` @@ -244,6 +244,6 @@ EXAMPLES $ sf lightning dev site --name "Partner Central" --target-org myOrg ``` -_See code: [src/commands/lightning/dev/site.ts](https://github.com/salesforcecli/plugin-lightning-dev/blob/1.2.0/src/commands/lightning/dev/site.ts)_ +_See code: [src/commands/lightning/dev/site.ts](https://github.com/salesforcecli/plugin-lightning-dev/blob/1.2.1-alpha.0/src/commands/lightning/dev/site.ts)_ diff --git a/package.json b/package.json index cfc63db0..67cdbb72 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/plugin-lightning-dev", "description": "Lightning development tools for LEX, Mobile, and Experience Sites", - "version": "1.2.0", + "version": "1.2.1-alpha.0", "author": "Salesforce", "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { From e263ab89062be834e3470ce6cae0d6ce75e02172 Mon Sep 17 00:00:00 2001 From: Nicolas Kruk Date: Fri, 20 Sep 2024 12:43:53 -0400 Subject: [PATCH 5/7] feat: cleanup / error messaging --- src/shared/experience/expSite.ts | 38 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/shared/experience/expSite.ts b/src/shared/experience/expSite.ts index d5789292..abc3947c 100644 --- a/src/shared/experience/expSite.ts +++ b/src/shared/experience/expSite.ts @@ -101,8 +101,19 @@ export class ExperienceSite { * @returns sid token for proxied site requests */ public async setupAuth(): Promise { - const networkId = await this.getNetworkId(); - const sidToken = await this.getNewSidToken(networkId); + let sidToken = ''; // Default to guest user access only + + // Use environment variable for now if users want to just have guest access only + if (process.env.SITE_GUEST_ACCESS !== 'true') { + try { + const networkId = await this.getNetworkId(); + sidToken = await this.getNewSidToken(networkId); + } catch (e) { + // eslint-disable-next-line no-console + console.error('Failed to establish authentication for site', e); + } + } + return sidToken; } @@ -238,7 +249,7 @@ export class ExperienceSite { return resourcePath; } - public async getNetworkId(): Promise { + private async getNetworkId(): Promise { const conn = this.org.getConnection(); // Query the Network object for the network with the given site name const result = await conn.query<{ Id: string }>(`SELECT Id FROM Network WHERE Name = '${this.siteDisplayName}'`); @@ -250,18 +261,18 @@ export class ExperienceSite { networkId = networkId.substring(0, networkId.length - 3); return networkId; } else { - throw new Error(`Network with name '${this.siteDisplayName}' not found`); + throw new Error(`NetworkId for site: '${this.siteDisplayName}' could not be found`); } } - public async getNewSidToken(networkId: string): Promise { + private async getNewSidToken(networkId: string): Promise { // Get the connection and access token from the org const conn = this.org.getConnection(); const orgId = this.org.getOrgId(); // Not sure if we need to do this const orgIdMinus3 = orgId.substring(0, orgId.length - 3); - const accessToken = conn.accessToken; // TODO should we be refreshing before use? + const accessToken = conn.accessToken; const instanceUrl = conn.instanceUrl; // Org URL // Call out to the servlet to establish a session @@ -269,7 +280,7 @@ export class ExperienceSite { // Make the GET request without following redirects if (accessToken) { - // TODO should we always refreshAuth? + // TODO should we try and refresh auth here? // await conn.refreshAuth(); const cookies = [`sid=${accessToken}`, `oid=${orgIdMinus3}`].join('; ').trim(); @@ -283,14 +294,14 @@ export class ExperienceSite { }); // Extract the Location header - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const locationHeader = response.headers['location']; + const locationHeader = response.headers['location'] as string; if (locationHeader) { // Parse the URL to extract the 'sid' parameter - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const urlObj = new URL(locationHeader); const sid = urlObj.searchParams.get('sid') ?? ''; const cookies2 = ['__Secure-has-sid=1', `sid=${sid}`, `oid=${orgIdMinus3}`].join('; ').trim(); + + // Request the location header to establish our session with the servlet response = await axios.get(urlObj.toString(), { headers: { Cookie: cookies2, @@ -301,11 +312,10 @@ export class ExperienceSite { }); const setCookieHeader = response.headers['set-cookie']; if (setCookieHeader) { - // 'set-cookie' can be an array if multiple cookies are set // Find the 'sid' cookie in the set-cookie header const sidCookie = setCookieHeader.find((cookieStr: string) => cookieStr.startsWith('sid=')); if (sidCookie) { - // Extract the sid value from the cookie string + // Extract the sid value from the set-cookie string const sidMatch = sidCookie.match(/sid=([^;]+)/); if (sidMatch?.[1]) { const sidToken = sidMatch[1]; @@ -314,13 +324,15 @@ export class ExperienceSite { } } } + + // if we can't establish a valid session this way, lets just warn the user and utilize the guest user context for the site // eslint-disable-next-line no-console console.warn( `Warning: could not establish valid auth token for your site '${this.siteDisplayName}'.` + 'Local Dev proxied requests to your site may fail or return data from the guest user context.' ); - return accessToken; + return ''; // Site will be guest user access only } // eslint-disable-next-line no-console console.warn( From 9c611120691b9f4eb8f6744be7b0ccec3b958e09 Mon Sep 17 00:00:00 2001 From: Nicolas Kruk Date: Fri, 20 Sep 2024 12:44:19 -0400 Subject: [PATCH 6/7] chore: more cleanup --- src/shared/experience/expSite.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shared/experience/expSite.ts b/src/shared/experience/expSite.ts index abc3947c..f9f9e6d6 100644 --- a/src/shared/experience/expSite.ts +++ b/src/shared/experience/expSite.ts @@ -275,14 +275,13 @@ export class ExperienceSite { const accessToken = conn.accessToken; const instanceUrl = conn.instanceUrl; // Org URL - // Call out to the servlet to establish a session - const switchUrl = `${instanceUrl}/servlet/networks/switch?networkId=${networkId}`; - // Make the GET request without following redirects if (accessToken) { // TODO should we try and refresh auth here? // await conn.refreshAuth(); + // Call out to the switcher servlet to establish a session + const switchUrl = `${instanceUrl}/servlet/networks/switch?networkId=${networkId}`; const cookies = [`sid=${accessToken}`, `oid=${orgIdMinus3}`].join('; ').trim(); let response = await axios.get(switchUrl, { headers: { @@ -293,7 +292,7 @@ export class ExperienceSite { validateStatus: (status) => status >= 200 && status < 400, // Accept 3xx status codes }); - // Extract the Location header + // Extract the Location callback header const locationHeader = response.headers['location'] as string; if (locationHeader) { // Parse the URL to extract the 'sid' parameter From 0986149a85a51458c9f76ba486157d8429a72b0e Mon Sep 17 00:00:00 2001 From: Nicolas Kruk Date: Fri, 20 Sep 2024 12:48:42 -0400 Subject: [PATCH 7/7] chore: comments --- src/shared/experience/expSite.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shared/experience/expSite.ts b/src/shared/experience/expSite.ts index f9f9e6d6..233dc7bc 100644 --- a/src/shared/experience/expSite.ts +++ b/src/shared/experience/expSite.ts @@ -333,6 +333,8 @@ export class ExperienceSite { return ''; // Site will be guest user access only } + + // Not sure what scenarios we don't have an access token at all, but lets output a separate message here so we can distinguish these edge cases // eslint-disable-next-line no-console console.warn( 'Warning: sf cli org connection missing accessToken. Local Dev proxied requests to your site may fail or return data from the guest user context.'