diff --git a/static/src/js/containers/AuthCallbackContainer/AuthCallbackContainer.js b/static/src/js/containers/AuthCallbackContainer/AuthCallbackContainer.js index 211a1f9105..e740ec52c9 100644 --- a/static/src/js/containers/AuthCallbackContainer/AuthCallbackContainer.js +++ b/static/src/js/containers/AuthCallbackContainer/AuthCallbackContainer.js @@ -4,6 +4,7 @@ import { set } from 'tiny-cookie' import { connect } from 'react-redux' import { parse } from 'qs' +import { getEnvironmentConfig } from '../../../../../sharedUtils/config' import { locationPropType } from '../../util/propTypes/location' import history from '../../util/history' @@ -28,6 +29,8 @@ export const AuthCallbackContainer = ({ location, onAddEarthdataDownloadRedirect }) => { + const { edscHost } = getEnvironmentConfig() + useEffect(() => { const { search } = location @@ -39,42 +42,41 @@ export const AuthCallbackContainer = ({ redirect = '/' } = params - // Verify that the redirect params are real URLs - try { - let redirectUrl - if (eddRedirect) redirectUrl = new URL(eddRedirect) - if (redirect && redirect !== '/') redirectUrl = new URL(redirect) - - if ( - redirectUrl - && redirectUrl.protocol !== 'http:' - && redirectUrl.protocol !== 'https:' - && redirectUrl.protocol !== 'earthdata-download:' - ) { - // The redirectUrl is not a valid protocol - console.log('The redirectUrl is not a valid protocol') - window.location.replace('/') + let eddRedirectUrl = eddRedirect + + if (redirect.includes('earthdata-download')) { + eddRedirectUrl = redirect + } + + // Handle EDD redirects + if (eddRedirectUrl) { + const validEddRedirect = eddRedirectUrl.startsWith('earthdata-download') + + if (validEddRedirect) { + if (accessToken) eddRedirectUrl += `&token=${accessToken}` + + // Add the redirect information to the store + onAddEarthdataDownloadRedirect({ + redirect: eddRedirectUrl + }) + + // Redirect to the edd callback + history.push('/earthdata-download-callback') return } - } catch (error) { - window.location.replace('/') + + window.location.replace('/not-found') return } - // If the redirect includes earthdata-download, redirect to the edd callback - if (eddRedirect || redirect.includes('earthdata-download')) { - let eddRedirectUrl = eddRedirect || redirect - if (accessToken) eddRedirectUrl += `&token=${accessToken}` - - // Add the redirect information to the store - onAddEarthdataDownloadRedirect({ - redirect: eddRedirectUrl - }) + // Handle redirects + const invalidRedirectUrl = redirect !== '/' && !redirect.startsWith(edscHost) - // Redirect to the edd callback - history.push('/earthdata-download-callback') + if (invalidRedirectUrl) { + // Redirect to an error page or a safe location if the URL is not a relative path + window.location.replace('/not-found') return } diff --git a/static/src/js/containers/AuthCallbackContainer/__tests__/AuthCallbackContainer.test.js b/static/src/js/containers/AuthCallbackContainer/__tests__/AuthCallbackContainer.test.js index a454aaf031..f72779e3de 100644 --- a/static/src/js/containers/AuthCallbackContainer/__tests__/AuthCallbackContainer.test.js +++ b/static/src/js/containers/AuthCallbackContainer/__tests__/AuthCallbackContainer.test.js @@ -154,7 +154,41 @@ describe('AuthCallbackContainer component', () => { expect(setSpy).toBeCalledTimes(0) expect(window.location.replace.mock.calls.length).toBe(1) - expect(window.location.replace.mock.calls[0]).toEqual(['/']) + expect(window.location.replace.mock.calls[0]).toEqual(['/not-found']) + }) + + test('does not follow the redirect if the redirect param is not relative to earthdata-search', () => { + const setSpy = jest.spyOn(tinyCookie, 'set') + delete window.location + window.location = { replace: jest.fn() } + + setup({ + location: { + search: '?redirect=https://evil.com' + } + }) + + expect(setSpy).toBeCalledTimes(0) + + expect(window.location.replace.mock.calls.length).toBe(1) + expect(window.location.replace.mock.calls[0]).toEqual(['/not-found']) + }) + + test('does not follow the eddRedirect it is not a valid earthdata-download redirect', () => { + const setSpy = jest.spyOn(tinyCookie, 'set') + delete window.location + window.location = { replace: jest.fn() } + + setup({ + location: { + search: '?eddRedirect=https://evil.com' + } + }) + + expect(setSpy).toBeCalledTimes(0) + + expect(window.location.replace.mock.calls.length).toBe(1) + expect(window.location.replace.mock.calls[0]).toEqual(['/not-found']) }) test('does not follow the redirect if the eddRedirect param is not valid', () => { @@ -171,6 +205,6 @@ describe('AuthCallbackContainer component', () => { expect(setSpy).toBeCalledTimes(0) expect(window.location.replace.mock.calls.length).toBe(1) - expect(window.location.replace.mock.calls[0]).toEqual(['/']) + expect(window.location.replace.mock.calls[0]).toEqual(['/not-found']) }) })