From 322a2be9ba97eb43ea0cdefb3fe9a1903087b33e Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Mon, 21 Oct 2024 13:55:41 -0400 Subject: [PATCH 1/7] When on localhost, links to OneSage should also be on localhost --- apps/SageAccountWeb/package.json | 1 + .../src/utils/hooks/useOneSageURL.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/SageAccountWeb/package.json b/apps/SageAccountWeb/package.json index 8013fbfd167..6a86b7083ef 100644 --- a/apps/SageAccountWeb/package.json +++ b/apps/SageAccountWeb/package.json @@ -72,6 +72,7 @@ "scripts": { "clean": "rimraf build coverage", "start": "vite", + "preview": "vite preview", "build": "vite build", "test": "vitest", "type-check": "tsc --noEmit" diff --git a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts index 2b2c72eb299..61bad051818 100644 --- a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts +++ b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts @@ -20,10 +20,16 @@ export function useOneSageURL( const { appId } = useSynapseContext() return useMemo(() => { - const targetURL = - window.location.hostname != 'staging.synapse.org' - ? ONE_SAGE_PRODUCTION_URL - : ONE_SAGE_STAGING_URL + let targetURL = ONE_SAGE_PRODUCTION_URL + if (window.location.hostname == 'staging.synapse.org') { + targetURL = ONE_SAGE_STAGING_URL + } else if ( + window.location.hostname == 'localhost' || + window.location.hostname == '127.0.0.1' + ) { + targetURL = `http://${window.location.hostname}:3000/` + } + const url = new URL(path, targetURL) if (appId) { url.searchParams.append(ONE_SAGE_APPID_QUERY_PARAM_KEY, appId) From f92d3e6f1677132402a153f588e694dc6ebde687 Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Mon, 21 Oct 2024 16:28:24 -0400 Subject: [PATCH 2/7] Always push to LoginPlace when clicking Login --- .../SynapseHomepageV2/SynapseHomepageNavBar.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/synapse-react-client/src/components/SynapseHomepageV2/SynapseHomepageNavBar.tsx b/packages/synapse-react-client/src/components/SynapseHomepageV2/SynapseHomepageNavBar.tsx index 2dc6713aa78..648bcc95511 100644 --- a/packages/synapse-react-client/src/components/SynapseHomepageV2/SynapseHomepageNavBar.tsx +++ b/packages/synapse-react-client/src/components/SynapseHomepageV2/SynapseHomepageNavBar.tsx @@ -87,7 +87,12 @@ export const SynapseHomepageNavBar: React.FunctionComponent< const handleClosePortalResources = () => { setPortalResourcesAnchorEl(null) } - const oneSageURL = useOneSageURL() + + const onLoginClicked = () => { + // Navigate to the LoginPlace, which will set a cookie that will be used to redirect back from OneSage + gotoPlace(LOGIN_LINK) + } + return ( Login @@ -273,7 +278,7 @@ export const SynapseHomepageNavBar: React.FunctionComponent< sx={{ mb: '40px' }} onClick={() => { handleCloseMobileMenu() - gotoPlace(LOGIN_LINK) + onLoginClicked() }} > Log In From a5cc08a0a16c5ae7faf76c87ddbca90e9aeb7acf Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Mon, 21 Oct 2024 16:32:56 -0400 Subject: [PATCH 3/7] Fix tests --- .../src/utils/hooks/useDetectSSOCode.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-react-client/src/utils/hooks/useDetectSSOCode.test.ts b/packages/synapse-react-client/src/utils/hooks/useDetectSSOCode.test.ts index ad519bdfa55..08a71327830 100644 --- a/packages/synapse-react-client/src/utils/hooks/useDetectSSOCode.test.ts +++ b/packages/synapse-react-client/src/utils/hooks/useDetectSSOCode.test.ts @@ -326,7 +326,7 @@ describe('useDetectSSOCode tests', () => { expect(mockSetAccessTokenCookie).not.toHaveBeenCalled() expect(onSignInComplete).not.toHaveBeenCalled() expect(window.location.replace).toHaveBeenCalledWith( - 'https://accounts.synapse.org/register1', + 'http://localhost:3000/register1', ) expect(hookReturn.result.current.isLoading).toBe(false) }) From 0adbdace9a39db1f7d0a8c1932aafd71c9b09b41 Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Tue, 22 Oct 2024 11:19:48 -0400 Subject: [PATCH 4/7] Make OneSage URL generation more comprehensive Fixes case where staging OneSage redirects to production OneSage --- apps/SageAccountWeb/src/AppInitializer.tsx | 5 +- .../src/AppInitializer.tsx | 10 +- .../src/utils/SynapseConstants.ts | 6 + .../src/utils/functions/getEndpoint.ts | 14 +- .../src/utils/hooks/useOneSageURL.test.ts | 144 ++++++++++++++++++ .../src/utils/hooks/useOneSageURL.ts | 102 +++++++++---- 6 files changed, 246 insertions(+), 35 deletions(-) create mode 100644 packages/synapse-react-client/src/utils/hooks/useOneSageURL.test.ts diff --git a/apps/SageAccountWeb/src/AppInitializer.tsx b/apps/SageAccountWeb/src/AppInitializer.tsx index c074ff32ea0..a435d95c5a4 100644 --- a/apps/SageAccountWeb/src/AppInitializer.tsx +++ b/apps/SageAccountWeb/src/AppInitializer.tsx @@ -10,6 +10,7 @@ import { SynapseUtilityFunctions, useApplicationSessionContext, useFramebuster, + SynapseConstants, } from 'synapse-react-client' import { AppContextProvider } from './AppContext' import { useSourceApp } from './components/useSourceApp' @@ -30,12 +31,12 @@ function AppInitializer(props: { children?: React.ReactNode }) { const isDev: boolean = window.location.hostname.includes('dev') const stagingConfig = { - REPO: 'https://repo-staging.prod.sagebase.org', + REPO: SynapseConstants.SYNAPSE_BACKEND_STAGING_URL, PORTAL: 'https://staging.synapse.org/', } const devConfig = { - REPO: 'https://repo-dev.dev.sagebase.org', + REPO: SynapseConstants.SYNAPSE_BACKEND_DEV_URL, PORTAL: 'https://portal-dev.dev.sagebase.org/', } diff --git a/apps/synapse-oauth-signin/src/AppInitializer.tsx b/apps/synapse-oauth-signin/src/AppInitializer.tsx index 2b560d0c0cc..440e12ac1a7 100644 --- a/apps/synapse-oauth-signin/src/AppInitializer.tsx +++ b/apps/synapse-oauth-signin/src/AppInitializer.tsx @@ -1,6 +1,10 @@ import { OAuthClientError } from './OAuthClientError' import React, { useCallback, useEffect } from 'react' -import { ApplicationSessionManager, useFramebuster } from 'synapse-react-client' +import { + ApplicationSessionManager, + useFramebuster, + SynapseConstants, +} from 'synapse-react-client' import { handleErrorRedirect } from './URLUtils' function AppInitializer( @@ -26,12 +30,12 @@ function AppInitializer( const isDev: boolean = window.location.hostname.includes('dev') const stagingConfig = { - REPO: 'https://repo-staging.prod.sagebase.org/', + REPO: SynapseConstants.SYNAPSE_BACKEND_STAGING_URL, PORTAL: 'https://staging.synapse.org/', } const devConfig = { - REPO: 'https://repo-dev.dev.sagebase.org/', + REPO: SynapseConstants.SYNAPSE_BACKEND_DEV_URL, PORTAL: 'https://portal-dev.dev.sagebase.org/', } diff --git a/packages/synapse-react-client/src/utils/SynapseConstants.ts b/packages/synapse-react-client/src/utils/SynapseConstants.ts index 58c525653a2..df749f3d4d4 100644 --- a/packages/synapse-react-client/src/utils/SynapseConstants.ts +++ b/packages/synapse-react-client/src/utils/SynapseConstants.ts @@ -195,6 +195,12 @@ export const PERSISTENT_LOCAL_STORAGE_KEYS = [ export const PRIVACY_POLICY_LINK = 'https://www.synapse.org/TrustCenter:PrivacyPolicy' +export const SYNAPSE_BACKEND_PRODUCTION_URL = + 'https://repo-prod.prod.sagebase.org' +export const SYNAPSE_BACKEND_STAGING_URL = + 'https://repo-staging.prod.sagebase.org' +export const SYNAPSE_BACKEND_DEV_URL = 'https://repo-dev.dev.sagebase.org' + export const ONE_SAGE_PRODUCTION_URL = 'https://accounts.synapse.org' export const ONE_SAGE_STAGING_URL = 'https://staging.accounts.synapse.org' export const ONE_SAGE_APPID_QUERY_PARAM_KEY = 'appId' diff --git a/packages/synapse-react-client/src/utils/functions/getEndpoint.ts b/packages/synapse-react-client/src/utils/functions/getEndpoint.ts index b230661325c..14f00925666 100644 --- a/packages/synapse-react-client/src/utils/functions/getEndpoint.ts +++ b/packages/synapse-react-client/src/utils/functions/getEndpoint.ts @@ -1,3 +1,9 @@ +import { + SYNAPSE_BACKEND_DEV_URL, + SYNAPSE_BACKEND_PRODUCTION_URL, + SYNAPSE_BACKEND_STAGING_URL, +} from '../SynapseConstants' + export enum BackendDestinationEnum { REPO_ENDPOINT, PORTAL_ENDPOINT, @@ -27,7 +33,7 @@ const DEFAULT_SYNAPSE_PORTAL = getSynapsePortalEndpoint( ) export const PRODUCTION_ENDPOINT_CONFIG: EndpointObject = { - REPO: 'https://repo-prod.prod.sagebase.org', + REPO: SYNAPSE_BACKEND_PRODUCTION_URL, PORTAL: DEFAULT_SYNAPSE_PORTAL, } @@ -57,15 +63,15 @@ const MOCK_PORTAL_ORIGIN = 'https://mock-portal.sagebase.org/' satisfies string export const STACK_MAP: Record = { production: { - REPO: 'https://repo-prod.prod.sagebase.org', + REPO: SYNAPSE_BACKEND_PRODUCTION_URL, PORTAL: 'https://www.synapse.org/', }, staging: { - REPO: 'https://repo-staging.prod.sagebase.org', + REPO: SYNAPSE_BACKEND_STAGING_URL, PORTAL: 'https://staging.synapse.org/', }, development: { - REPO: 'https://repo-dev.dev.sagebase.org', + REPO: SYNAPSE_BACKEND_DEV_URL, PORTAL: 'https://portal-dev.dev.sagebase.org/', }, mock: { diff --git a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.test.ts b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.test.ts new file mode 100644 index 00000000000..2aac6cb40e1 --- /dev/null +++ b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.test.ts @@ -0,0 +1,144 @@ +import { + SYNAPSE_BACKEND_DEV_URL, + SYNAPSE_BACKEND_PRODUCTION_URL, + SYNAPSE_BACKEND_STAGING_URL, +} from '../SynapseConstants' +import { getOneSageUrl } from './useOneSageURL' + +describe('OneSage URL tests', () => { + describe('SynapseWebClient domains', () => { + test('production', () => { + const appId = 'synapse.org' + expect( + getOneSageUrl( + 'synapse.org', + SYNAPSE_BACKEND_PRODUCTION_URL, + appId, + ).toString(), + ).toEqual('https://accounts.synapse.org/?appId=synapse.org') + expect( + getOneSageUrl( + 'www.synapse.org', + SYNAPSE_BACKEND_PRODUCTION_URL, + appId, + ).toString(), + ).toEqual('https://accounts.synapse.org/?appId=synapse.org') + }) + test('staging', () => { + const appId = 'staging.synapse.org' + const url = getOneSageUrl( + 'staging.synapse.org', + SYNAPSE_BACKEND_STAGING_URL, + appId, + ) + expect(url.toString()).toEqual( + 'https://staging.accounts.synapse.org/?appId=staging.synapse.org', + ) + }) + test.todo('dev') // IT-3849 + test('local', () => { + const appId = 'localhost' + expect( + getOneSageUrl( + '127.0.0.1', + SYNAPSE_BACKEND_PRODUCTION_URL, + appId, + ).toString(), + ).toEqual('http://127.0.0.1:3000/?appId=localhost') + expect( + getOneSageUrl( + '127.0.0.1', + SYNAPSE_BACKEND_STAGING_URL, + appId, + ).toString(), + ).toEqual('http://127.0.0.1:3000/?appId=localhost') + expect( + getOneSageUrl('127.0.0.1', SYNAPSE_BACKEND_DEV_URL, appId).toString(), + ).toEqual('http://127.0.0.1:3000/?appId=localhost') + expect( + getOneSageUrl( + 'localhost', + SYNAPSE_BACKEND_PRODUCTION_URL, + appId, + ).toString(), + ).toEqual('http://localhost:3000/?appId=localhost') + expect( + getOneSageUrl( + 'localhost', + SYNAPSE_BACKEND_STAGING_URL, + appId, + ).toString(), + ).toEqual('http://localhost:3000/?appId=localhost') + expect( + getOneSageUrl('localhost', SYNAPSE_BACKEND_DEV_URL, appId).toString(), + ).toEqual('http://localhost:3000/?appId=localhost') + }) + }) + + describe('OneSage domains', () => { + test('production', () => { + const url = getOneSageUrl( + 'accounts.synapse.org', + SYNAPSE_BACKEND_PRODUCTION_URL, + ) + expect(url.toString()).toEqual('https://accounts.synapse.org/') + }) + test('staging', () => { + const url = getOneSageUrl( + 'staging.accounts.synapse.org', + SYNAPSE_BACKEND_STAGING_URL, + ) + expect(url.toString()).toEqual('https://staging.accounts.synapse.org/') + }) + test.todo('dev') // no site exists (IT-3849) + test('local', () => { + const url = getOneSageUrl('localhost', SYNAPSE_BACKEND_PRODUCTION_URL) + expect(url.toString()).toEqual('http://localhost:3000/') + }) + }) + + describe('synapse-oauth-signin domains', () => { + test('production', () => { + const url = getOneSageUrl( + 'signin.synapse.org', + SYNAPSE_BACKEND_PRODUCTION_URL, + ) + expect(url.toString()).toEqual('https://accounts.synapse.org/') + }) + test('staging', () => { + const url = getOneSageUrl( + 'staging-signin.synapse.org', + SYNAPSE_BACKEND_STAGING_URL, + ) + expect(url.toString()).toEqual('https://staging.accounts.synapse.org/') + }) + test.todo('dev') // no site exists + test.todo('local') // these typically run on the same port, so we need to establish a convention to run them on different ports + }) + + describe('portal domain', () => { + const appId = 'myportal' + + test('production', () => { + const url = getOneSageUrl( + 'myportal.synapse.org', + SYNAPSE_BACKEND_PRODUCTION_URL, + appId, + ) + expect(url.toString()).toEqual( + 'https://accounts.synapse.org/?appId=myportal', + ) + }) + test('staging', () => { + // Staging portals typically use Synapse production as a backend + const url = getOneSageUrl( + 'staging.myportal.synapse.org', + SYNAPSE_BACKEND_PRODUCTION_URL, + appId, + ) + expect(url.toString()).toEqual( + 'https://accounts.synapse.org/?appId=myportal', + ) + }) + }) +}) diff --git a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts index 61bad051818..5a23069e0fc 100644 --- a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts +++ b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts @@ -1,11 +1,70 @@ -import { useSynapseContext } from '../context' import { useMemo } from 'react' +import { useSynapseContext } from '../context' +import { BackendDestinationEnum, getEndpoint } from '../functions/index' import { ONE_SAGE_APPID_QUERY_PARAM_KEY, ONE_SAGE_PRODUCTION_URL, ONE_SAGE_STAGING_URL, + SYNAPSE_BACKEND_PRODUCTION_URL, + SYNAPSE_BACKEND_STAGING_URL, } from '../SynapseConstants' +export function getOneSageBaseUrl( + currentHostname: string, + currentBackendEndpoint: string, +) { + // If we're on synapse.org, then go to the accounts site that matches the current backend stack. + if ( + currentHostname === 'synapse.org' || + currentHostname.endsWith('.synapse.org') + ) { + if (currentBackendEndpoint === SYNAPSE_BACKEND_PRODUCTION_URL) { + return ONE_SAGE_PRODUCTION_URL + } + if (currentBackendEndpoint === SYNAPSE_BACKEND_STAGING_URL) { + return ONE_SAGE_STAGING_URL + } + } + + if (currentHostname.endsWith('.sagebase.org')) { + // TODO: Return the dev accounts site created in IT-3849 + } + + if (currentHostname === 'localhost' || currentHostname === '127.0.0.1') { + return `http://${currentHostname}:3000/` + } + + console.warn( + `No accounts URL found for host: ${currentHostname} with backend endpoint: ${currentBackendEndpoint}`, + ) + return ONE_SAGE_PRODUCTION_URL +} + +export function getOneSageUrl( + currentHostname: string, + currentBackendEndpoint: string, + appId?: string, + path: string = '', + search?: URLSearchParams, + hash?: string, +) { + const targetURL = getOneSageBaseUrl(currentHostname, currentBackendEndpoint) + + const url = new URL(path, targetURL) + if (appId) { + url.searchParams.append(ONE_SAGE_APPID_QUERY_PARAM_KEY, appId) + } + if (search) { + search.forEach((value, key) => { + url.searchParams.append(key, value) + }) + } + if (hash) { + url.hash = hash + } + return url +} + /** * Create a URL to OneSage that includes the current app's ID using SynapseContext * @param path the path to the OneSage page @@ -16,32 +75,23 @@ export function useOneSageURL( path: string = '', search?: URLSearchParams, hash?: string, -) { +): URL { const { appId } = useSynapseContext() - return useMemo(() => { - let targetURL = ONE_SAGE_PRODUCTION_URL - if (window.location.hostname == 'staging.synapse.org') { - targetURL = ONE_SAGE_STAGING_URL - } else if ( - window.location.hostname == 'localhost' || - window.location.hostname == '127.0.0.1' - ) { - targetURL = `http://${window.location.hostname}:3000/` - } + const currentBackendEndpoint = getEndpoint( + BackendDestinationEnum.REPO_ENDPOINT, + ) - const url = new URL(path, targetURL) - if (appId) { - url.searchParams.append(ONE_SAGE_APPID_QUERY_PARAM_KEY, appId) - } - if (search) { - search.forEach((value, key) => { - url.searchParams.append(key, value) - }) - } - if (hash) { - url.hash = hash - } - return url - }, [appId, hash, path, search]) + return useMemo( + () => + getOneSageUrl( + window.location.host.toLowerCase(), + currentBackendEndpoint, + appId, + path, + search, + hash, + ), + [currentBackendEndpoint, appId, path, search, hash], + ) } From 5118461956d2a396e3a8d8cdb86a3d3c271611c2 Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Tue, 22 Oct 2024 11:20:28 -0400 Subject: [PATCH 5/7] Fix test --- .../src/components/Authentication/Login.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-react-client/src/components/Authentication/Login.test.tsx b/packages/synapse-react-client/src/components/Authentication/Login.test.tsx index df32684e91a..13448ac6cf5 100644 --- a/packages/synapse-react-client/src/components/Authentication/Login.test.tsx +++ b/packages/synapse-react-client/src/components/Authentication/Login.test.tsx @@ -255,7 +255,7 @@ describe('StandaloneLoginForm', () => { ) expect(callback).not.toHaveBeenCalled() expect(window.location.assign).toHaveBeenCalledWith( - 'https://accounts.synapse.org/changePassword?errorCode=PASSWORD_RESET_VIA_EMAIL_REQUIRED', + 'http://localhost:3000/changePassword?errorCode=PASSWORD_RESET_VIA_EMAIL_REQUIRED', ) }) }) From b9fea013a979e81efbb67e60573dbf1259205ed6 Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Tue, 22 Oct 2024 11:41:08 -0400 Subject: [PATCH 6/7] Fix tests --- packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts index 5a23069e0fc..2ec1f4145fb 100644 --- a/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts +++ b/packages/synapse-react-client/src/utils/hooks/useOneSageURL.ts @@ -85,7 +85,7 @@ export function useOneSageURL( return useMemo( () => getOneSageUrl( - window.location.host.toLowerCase(), + window.location.hostname.toLowerCase(), currentBackendEndpoint, appId, path, From c9e56db85400e33c6d05790e1dd336fc7196dca4 Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Tue, 22 Oct 2024 12:08:16 -0400 Subject: [PATCH 7/7] Fix snapshot --- .../__snapshots__/SynapseHomepageV2.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/synapse-react-client/src/components/SynapseHomepageV2/__snapshots__/SynapseHomepageV2.test.tsx.snap b/packages/synapse-react-client/src/components/SynapseHomepageV2/__snapshots__/SynapseHomepageV2.test.tsx.snap index dd7e1e7cc00..4b9fcee8f2b 100644 --- a/packages/synapse-react-client/src/components/SynapseHomepageV2/__snapshots__/SynapseHomepageV2.test.tsx.snap +++ b/packages/synapse-react-client/src/components/SynapseHomepageV2/__snapshots__/SynapseHomepageV2.test.tsx.snap @@ -743,7 +743,7 @@ exports[`SynapseHomepageV2 Snapshot test Basic home page 1`] = ` /> @@ -913,7 +913,7 @@ exports[`SynapseHomepageV2 Snapshot test Basic home page 1`] = ` Register Now