From f19ba934b700796744e26c500874fbe8aaa1a1bd Mon Sep 17 00:00:00 2001 From: ajay-sentry <159853603+ajay-sentry@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:11:19 -0700 Subject: [PATCH] sec: 390 - Add validation for potential XSS vuln (#2797) * add tests, and validation for provider * add back supportServiceless param --- src/shared/api/api.js | 8 +++---- src/shared/api/api.test.js | 48 ++++++++++++++++++++++++++++++++++++++ src/shared/api/helpers.ts | 2 +- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/shared/api/api.js b/src/shared/api/api.js index b07199c360..f9ff70b9a6 100644 --- a/src/shared/api/api.js +++ b/src/shared/api/api.js @@ -5,7 +5,7 @@ import config from 'config' import { camelizeKeys } from 'shared/utils/camelizeKeys' import { snakeifyKeys } from 'shared/utils/snakeifyKeys' -import { generatePath, getHeaders } from './helpers' +import { generatePath, getHeaders, isProvider } from './helpers' function _fetch({ path, @@ -62,10 +62,10 @@ function graphql({ signal, supportsServiceless = false, }) { - let uri = `${config.API_URL}/graphql/${provider}` + let uri = `${config.API_URL}/graphql/` - if (supportsServiceless && !provider) { - uri = `${config.API_URL}/graphql/` + if (provider && isProvider(provider) && !supportsServiceless) { + uri = `${config.API_URL}/graphql/${provider}` } const headers = { diff --git a/src/shared/api/api.test.js b/src/shared/api/api.test.js index 623d4679fb..93c50308cf 100644 --- a/src/shared/api/api.test.js +++ b/src/shared/api/api.test.js @@ -4,6 +4,7 @@ import { setupServer } from 'msw/node' import config from 'config' import Api from './api' +import { AllProvidersArray } from './helpers' const rawUserData = { profile: { @@ -223,6 +224,53 @@ describe('when using a graphql request', () => { }) }) + describe('when different strings entered as provider', () => { + let fetchMock + afterEach(() => { + global.fetch.mockRestore() + }) + + it('does not have the provider in the url for non-provider', async () => { + fetchMock = jest.fn((url, options) => { + expect(url).toBe(`${config.API_URL}/graphql/`) + return Promise.resolve({ + ok: true, + json: async () => ({ data: { example: 'dummy data' } }), + }) + }) + + jest.spyOn(global, 'fetch').mockImplementation(fetchMock) + + await Api.graphql({ + provider: 'random hacks and stuff', + query: 'query MyInfo { me }', + }) + + expect(fetchMock).toHaveBeenCalled() + }) + test.each(AllProvidersArray)( + 'has the provider in the url for %s', + async (provider) => { + fetchMock = jest.fn((url, options) => { + expect(url).toBe(`${config.API_URL}/graphql/${provider}`) + return Promise.resolve({ + ok: true, + json: async () => ({ data: { example: 'dummy data' } }), + }) + }) + + jest.spyOn(global, 'fetch').mockImplementation(fetchMock) + + await Api.graphql({ + provider: provider, + query: 'query MyInfo { me }', + }) + + expect(fetchMock).toHaveBeenCalled() + } + ) + }) + describe('the request is unsuccessful', () => { it('returns the error status code', async () => { const data = Api.graphql({ diff --git a/src/shared/api/helpers.ts b/src/shared/api/helpers.ts index 1074953ab9..3593dac890 100644 --- a/src/shared/api/helpers.ts +++ b/src/shared/api/helpers.ts @@ -13,7 +13,7 @@ export interface NetworkErrorObject { dev: `${string} - ${number} ${string}` } -const AllProvidersArray = [ +export const AllProvidersArray = [ 'gh', 'gl', 'bb',