Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In this PR we remove the general SettingService cache, as it will not work across multiple horizontal unleash instances, events are not published across. We also fix the CORS origin to: - Access-Control-Allow-Origin set to "*" if no Origin is configured - Access-Control-Allow-Origin set to "*" if any Origin is configured to "*" - - Access-Control-Allow-Origin set to array and have the "cors" middleware to return an exact match on the user provided Origin. Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
- Loading branch information
1 parent
db7b39a
commit 09c87c7
Showing
11 changed files
with
218 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,152 @@ | ||
import { allowRequestOrigin } from './cors-origin-middleware'; | ||
import { resolveOrigin } from './cors-origin-middleware'; | ||
import FakeSettingStore from '../../test/fixtures/fake-setting-store'; | ||
import SettingService from '../services/setting-service'; | ||
import { createTestConfig } from '../../test/config/test-config'; | ||
import FakeEventStore from '../../test/fixtures/fake-event-store'; | ||
import { randomId } from '../util/random-id'; | ||
import { frontendSettingsKey } from '../types/settings/frontend-settings'; | ||
import FakeProjectStore from '../../test/fixtures/fake-project-store'; | ||
import { ProxyService, SettingService } from '../../lib/services'; | ||
import { ISettingStore } from '../../lib/types'; | ||
import { frontendSettingsKey } from '../../lib/types/settings/frontend-settings'; | ||
import { minutesToMilliseconds } from 'date-fns'; | ||
|
||
const createSettingService = (frontendApiOrigins: string[]): SettingService => { | ||
const createSettingService = ( | ||
frontendApiOrigins: string[], | ||
): { proxyService: ProxyService; settingStore: ISettingStore } => { | ||
const config = createTestConfig({ frontendApiOrigins }); | ||
|
||
const stores = { | ||
settingStore: new FakeSettingStore(), | ||
eventStore: new FakeEventStore(), | ||
projectStore: new FakeProjectStore(), | ||
}; | ||
|
||
return new SettingService(stores, config); | ||
const services = { | ||
settingService: new SettingService(stores, config), | ||
}; | ||
|
||
return { | ||
//@ts-ignore | ||
proxyService: new ProxyService(config, stores, services), | ||
settingStore: stores.settingStore, | ||
}; | ||
}; | ||
|
||
test('allowRequestOrigin', () => { | ||
test('resolveOrigin', () => { | ||
const dotCom = 'https://example.com'; | ||
const dotOrg = 'https://example.org'; | ||
|
||
expect(allowRequestOrigin('', [])).toEqual(false); | ||
expect(allowRequestOrigin(dotCom, [])).toEqual(false); | ||
expect(allowRequestOrigin(dotCom, [dotOrg])).toEqual(false); | ||
|
||
expect(allowRequestOrigin(dotCom, [dotCom, dotOrg])).toEqual(true); | ||
expect(allowRequestOrigin(dotCom, [dotOrg, dotCom])).toEqual(true); | ||
expect(allowRequestOrigin(dotCom, [dotCom, dotCom])).toEqual(true); | ||
|
||
expect(allowRequestOrigin(dotCom, ['*'])).toEqual(true); | ||
expect(allowRequestOrigin(dotCom, [dotOrg, '*'])).toEqual(true); | ||
expect(allowRequestOrigin(dotCom, [dotCom, dotOrg, '*'])).toEqual(true); | ||
expect(resolveOrigin([])).toEqual('*'); | ||
expect(resolveOrigin(['*'])).toEqual('*'); | ||
expect(resolveOrigin([dotOrg])).toEqual([dotOrg]); | ||
expect(resolveOrigin([dotCom, dotOrg])).toEqual([dotCom, dotOrg]); | ||
expect(resolveOrigin([dotOrg, '*'])).toEqual('*'); | ||
}); | ||
|
||
test('corsOriginMiddleware origin validation', async () => { | ||
const service = createSettingService([]); | ||
const { proxyService } = createSettingService([]); | ||
const userName = randomId(); | ||
await expect(() => | ||
service.setFrontendSettings({ frontendApiOrigins: ['a'] }, userName), | ||
proxyService.setFrontendSettings( | ||
{ frontendApiOrigins: ['a'] }, | ||
userName, | ||
), | ||
).rejects.toThrow('Invalid origin: a'); | ||
proxyService.destroy(); | ||
}); | ||
|
||
test('corsOriginMiddleware without config', async () => { | ||
const service = createSettingService([]); | ||
const { proxyService, settingStore } = createSettingService([]); | ||
const userName = randomId(); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: [], | ||
}); | ||
await service.setFrontendSettings({ frontendApiOrigins: [] }, userName); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
await proxyService.setFrontendSettings( | ||
{ frontendApiOrigins: [] }, | ||
userName, | ||
); | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: [], | ||
}); | ||
await service.setFrontendSettings({ frontendApiOrigins: ['*'] }, userName); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
await proxyService.setFrontendSettings( | ||
{ frontendApiOrigins: ['*'] }, | ||
userName, | ||
); | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: ['*'], | ||
}); | ||
await service.delete(frontendSettingsKey, userName); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
await settingStore.delete(frontendSettingsKey); | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: [], | ||
}); | ||
proxyService.destroy(); | ||
}); | ||
|
||
test('corsOriginMiddleware with config', async () => { | ||
const service = createSettingService(['*']); | ||
const { proxyService, settingStore } = createSettingService(['*']); | ||
const userName = randomId(); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: ['*'], | ||
}); | ||
await service.setFrontendSettings({ frontendApiOrigins: [] }, userName); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
await proxyService.setFrontendSettings( | ||
{ frontendApiOrigins: [] }, | ||
userName, | ||
); | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: [], | ||
}); | ||
await service.setFrontendSettings( | ||
await proxyService.setFrontendSettings( | ||
{ frontendApiOrigins: ['https://example.com', 'https://example.org'] }, | ||
userName, | ||
); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: ['https://example.com', 'https://example.org'], | ||
}); | ||
await service.delete(frontendSettingsKey, userName); | ||
expect(await service.getFrontendSettings()).toEqual({ | ||
await settingStore.delete(frontendSettingsKey); | ||
expect(await proxyService.getFrontendSettings(false)).toEqual({ | ||
frontendApiOrigins: ['*'], | ||
}); | ||
proxyService.destroy(); | ||
}); | ||
|
||
test('corsOriginMiddleware with caching enabled', async () => { | ||
jest.useFakeTimers(); | ||
|
||
const { proxyService } = createSettingService([]); | ||
|
||
const userName = randomId(); | ||
expect(await proxyService.getFrontendSettings()).toEqual({ | ||
frontendApiOrigins: [], | ||
}); | ||
|
||
//setting | ||
await proxyService.setFrontendSettings( | ||
{ frontendApiOrigins: ['*'] }, | ||
userName, | ||
); | ||
|
||
//still get cached value | ||
expect(await proxyService.getFrontendSettings()).toEqual({ | ||
frontendApiOrigins: [], | ||
}); | ||
|
||
jest.advanceTimersByTime(minutesToMilliseconds(2)); | ||
|
||
jest.useRealTimers(); | ||
|
||
/* | ||
This is needed because it is not enough to fake time to test the | ||
updated cache, we also need to make sure that all promises are | ||
executed and completed, in the right order. | ||
*/ | ||
await new Promise<void>((resolve) => | ||
process.nextTick(async () => { | ||
const settings = await proxyService.getFrontendSettings(); | ||
|
||
expect(settings).toEqual({ | ||
frontendApiOrigins: ['*'], | ||
}); | ||
resolve(); | ||
}), | ||
); | ||
proxyService.destroy(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.