Skip to content

Commit

Permalink
fix: adds SDK Key format validation for JS SDK to make sure key start…
Browse files Browse the repository at this point in the history
…s with client or dvc_client
  • Loading branch information
kaushalkapasi committed Aug 7, 2024
1 parent a20e243 commit 4d9791e
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 75 deletions.
120 changes: 71 additions & 49 deletions sdk/js/__tests__/Client.spec.js

Large diffs are not rendered by default.

33 changes: 19 additions & 14 deletions sdk/js/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ jest.spyOn(Request, 'getConfigJson').mockImplementation(() => {
return Promise.resolve({})
})

const test_key = 'client_test_sdk_key'
const missingKeyError = 'Missing SDK key! Call initialize with a valid SDK key'
const invalidKeyError =
'Invalid SDK key! SDK key must start with "client_" or "dvc_client_"'
const missingUserError = 'Missing user! Call initialize with a valid user'
const invalidUserError =
'Must have a user_id, or have "isAnonymous" set on the user'
Expand All @@ -16,16 +19,16 @@ const invalidOptionsError =
describe('initializeDevCycle tests', () => {
it('should return client for initialize and initializeDevCycle', () => {
const user = { user_id: 'user1' }
let client = DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID', user)
let client = DVC.initializeDevCycle(test_key, user)
expect(client).not.toBeNull()

client = DVC.initialize('YOUR_CLIENT_SIDE_ID', user)
client = DVC.initialize(test_key, user)
expect(client).not.toBeNull()
})

it('should return client when calling initialize', () => {
const user = { user_id: 'user1' }
const client = DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID', user)
const client = DVC.initializeDevCycle(test_key, user)
expect(client).not.toBeNull()
})

Expand All @@ -34,31 +37,33 @@ describe('initializeDevCycle tests', () => {
expect(() => DVC.initializeDevCycle()).toThrow(missingKeyError)
})

it('should throw an error if invalid SDK key is passed in initialize', () => {
expect(() => DVC.initializeDevCycle('bad_key')).toThrow(invalidKeyError)
})

it('should throw an error if user is not passed in initialize', () => {
expect(() => DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID')).toThrow(
missingUserError,
)
expect(() => DVC.initializeDevCycle(test_key)).toThrow(missingUserError)
})

it('should NOT throw an error if invalid user is passed in initialize', () => {
const badUser = { who: 'me' }
const client = DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID', badUser)
const client = DVC.initializeDevCycle(test_key, badUser)
expect(client).not.toBeNull()
})

it('should throw an error if invalid options are passed in initialize', () => {
const user = { user_id: 'user1' }
expect(() =>
DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID', user, null),
).toThrow(invalidOptionsError)
expect(() =>
DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID', user, false),
).toThrow(invalidOptionsError)
expect(() => DVC.initializeDevCycle(test_key, user, null)).toThrow(
invalidOptionsError,
)
expect(() => DVC.initializeDevCycle(test_key, user, false)).toThrow(
invalidOptionsError,
)
})

it('should flush when pagehide is triggered', () => {
const user = { user_id: 'bruh' }
const client = DVC.initializeDevCycle('YOUR_CLIENT_SIDE_ID', user)
const client = DVC.initializeDevCycle(test_key, user)
const flushMock = jest.fn()
client.flushEvents = flushMock

Expand Down
12 changes: 7 additions & 5 deletions sdk/js/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,32 @@ type VariableTypes = {
my_array_json: { test: string[] }
}

const test_key = 'client_test_sdk_key'

describe('initialize', () => {
it('allows a generic to be passed to initialize', () => {
const client = initializeDevCycle<VariableTypes>('test', {
const client = initializeDevCycle<VariableTypes>(test_key, {
user_id: 'test',
})
client.variableValue('my_array_json', { test: [] })
// @ts-expect-error - should not allow invalid variable keys
client.variableValue('bad-key', false)
})
it('should use second arg as options instead of user in deferred mode', () => {
const client = initializeDevCycle('test', {
const client = initializeDevCycle(test_key, {
deferInitialization: true,
})
expect(client.user).toBeUndefined()
})
it('should use the second arg as user when not in deferred mode', async () => {
const client = initializeDevCycle('test', {
const client = initializeDevCycle(test_key, {
user_id: 'test',
})
expect(client.user).toBeDefined()
})
it('should use the second arg as user when deferred mode is explicitly off', async () => {
const client = initializeDevCycle(
'test',
test_key,
{
user_id: 'test',
},
Expand All @@ -43,7 +45,7 @@ describe('initialize', () => {
})
it('should not allow no user when deferred mode is explicitly off', async () => {
expect(() =>
initializeDevCycle('test', {
initializeDevCycle(test_key, {
// @ts-expect-error - should not allow no user when deferred mode is explicitly off
deferInitialization: false,
}),
Expand Down
6 changes: 6 additions & 0 deletions sdk/js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ export function initializeDevCycle<
throw new Error('Missing SDK key! Call initialize with a valid SDK key')
}

if (!sdkKey.startsWith('client') && !sdkKey.startsWith('dvc_client')) {
throw new Error(
'Invalid SDK key! SDK key must start with "client_" or "dvc_client_"',
)
}

const userAndOptions = determineUserAndOptions(userOrOptions, optionsArg)
const { options } = userAndOptions
const isServiceWorker = checkIsServiceWorker()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function initOFClient(): Promise<{
}> {
const options = { logger }
OpenFeature.setContext({ targetingKey: 'node_sdk_test' })
const provider = new DevCycleProvider('DVC_SERVER_SDK_KEY', options)
const provider = new DevCycleProvider('dvc_client_sdk_key', options)
await OpenFeature.setProviderAndWait(provider)

if (provider.devcycleClient) {
Expand Down
10 changes: 6 additions & 4 deletions sdk/react/src/useIsDevCycleInitialized.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import fetch from 'cross-fetch'
global.fetch = fetch
jest.unmock('@devcycle/js-client-sdk')

const test_key = 'dvc_client_test_key'

describe('useIsDevCycleInitialized', () => {
it('should render the app once the SDK initializes', async () => {
const scope = nock('https://sdk-api.devcycle.com/v1')
Expand All @@ -38,7 +40,7 @@ describe('useIsDevCycleInitialized', () => {

const App = withDevCycleProvider({
user: { user_id: 'test_user' },
sdkKey: 'dvc_test_key',
sdkKey: test_key,
})(TestApp)

render(<App />)
Expand Down Expand Up @@ -73,7 +75,7 @@ describe('useIsDevCycleInitialized', () => {
}

const App = withDevCycleProvider({
sdkKey: 'dvc_test_key',
sdkKey: test_key,
options: {
deferInitialization: true,
},
Expand Down Expand Up @@ -103,7 +105,7 @@ describe('useIsDevCycleInitialized', () => {
}

const App = withDevCycleProvider({
sdkKey: 'dvc_test_key',
sdkKey: test_key,
user: { user_id: 'test_user' },
options: {
bootstrapConfig: {} as BucketedUserConfig,
Expand Down Expand Up @@ -150,7 +152,7 @@ describe('useIsDevCycleInitialized', () => {

const App = withDevCycleProvider({
user: { user_id: 'test_user' },
sdkKey: 'dvc_test_key',
sdkKey: test_key,
})(TestApp)

render(<App />)
Expand Down
4 changes: 3 additions & 1 deletion sdk/react/src/useVariableValue.integration.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import fetch from 'cross-fetch'
global.fetch = fetch
jest.unmock('@devcycle/js-client-sdk')

const test_key = 'dvc_client_test_key'

describe('useVariableValue', () => {
const Component = () => {
const variableValue = useVariableValue('string-var', 'Hello')
Expand Down Expand Up @@ -75,7 +77,7 @@ describe('useVariableValue', () => {

const App = withDevCycleProvider({
user: { user_id: 'test_user' },
sdkKey: 'dvc_test_key',
sdkKey: test_key,
})(TestApp)

render(<App />)
Expand Down
3 changes: 2 additions & 1 deletion sdk/react/src/useVariableValue.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import { mockSubscribeFunction } from '@devcycle/js-client-sdk' // defined in th

jest.mock('@devcycle/js-client-sdk')

const test_key = 'dvc_client_test_key'
const ProviderWrapper = ({ children }: { children: ReactElement }) => {
return (
<DevCycleProvider
config={{
user: { user_id: 'test', isAnonymous: false },
sdkKey: 'test',
sdkKey: test_key,
}}
>
{children}
Expand Down

0 comments on commit 4d9791e

Please sign in to comment.