Skip to content

Commit

Permalink
fix: improve endpoint creation
Browse files Browse the repository at this point in the history
  • Loading branch information
sshelomentsev committed Dec 13, 2023
1 parent 8f0aeff commit 006c91b
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 7 deletions.
3 changes: 3 additions & 0 deletions proxy/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export const handler = async (event: CloudFrontRequestEvent): Promise<CloudFront
if (resultPathMatches && resultPathMatches.length >= 1) {
suffix = resultPathMatches[1] ?? ''
}
if (suffix.length > 0 && !suffix.startsWith('/')) {
suffix = '/' + suffix
}
const eTLDPlusOneDomain = getEffectiveTLDPlusOne(getHost(request))
return handleResult({
region: getRegion(request, logger),
Expand Down
9 changes: 7 additions & 2 deletions proxy/handlers/handleResult.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ResultOptions } from '../model'
import { CloudFrontResultResponse } from 'aws-lambda'
import https from 'https'
import { Region } from '../model'

import { updateResponseHeaders, addTrafficMonitoringSearchParamsForVisitorIdRequest } from '../utils'

Expand All @@ -13,8 +14,12 @@ export function handleResult(options: ResultOptions): Promise<CloudFrontResultRe
const url = new URL(getIngressAPIHost(options.region) + options.suffix)
decodeURIComponent(options.querystring)
.split('&')
.filter((it) => it.includes('='))
.forEach((it) => {
const kv = it.split('=')
if (kv[0] === 'region') {
kv[1] = options.region
}
url.searchParams.append(kv[0], kv[1])
})
addTrafficMonitoringSearchParamsForVisitorIdRequest(url)
Expand Down Expand Up @@ -98,7 +103,7 @@ function generateRequestUniqueId(): string {
return generateRandomString(2)
}

function getIngressAPIHost(region: string): string {
const prefix = region === 'us' ? '' : `${region}.`
function getIngressAPIHost(region: Region): string {
const prefix = region === Region.us ? '' : `${region}.`
return `https://${prefix}__INGRESS_API__`
}
5 changes: 5 additions & 0 deletions proxy/model/Region.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum Region {
us = 'us',
eu = 'eu',
ap = 'ap',
}
3 changes: 2 additions & 1 deletion proxy/model/ResultOptions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { OutgoingHttpHeaders } from 'http'
import { Logger } from '../logger'
import { Region } from './'

export interface ResultOptions {
region: string
region: Region
querystring: string
method: string
headers: OutgoingHttpHeaders
Expand Down
3 changes: 2 additions & 1 deletion proxy/model/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AgentOptions } from './AgentOptions'
import { ResultOptions } from './ResultOptions'
import { Region } from './Region'

export { AgentOptions, ResultOptions }
export { AgentOptions, ResultOptions, Region }
8 changes: 6 additions & 2 deletions proxy/test/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ export function getMockSecretsManager() {
}
}

export const mockRequest = (uri: string, querystring = 'apiKey=ujKG34hUYKLJKJ1F&version=3&loaderVersion=3.6.2') => {
export const mockRequest = (
uri: string,
querystring = 'apiKey=ujKG34hUYKLJKJ1F&version=3&loaderVersion=3.6.2',
method = 'POST',
) => {
return {
clientIp: '1.1.1.1',
method: 'GET',
method: method,
uri,
querystring,
headers: {
Expand Down
84 changes: 84 additions & 0 deletions proxy/test/handlers/handleResult.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,90 @@ describe('Result Endpoint', function () {
)
})

test('Call with wrong region', async () => {
const queryString = 'apiKey=ujKG34hUYKLJKJ1F&version=3&loaderVersion=3.6.2'
const request = mockRequest('/behavior/result', queryString)
request.querystring = `${request.querystring}&region=bar.baz/foo`
const event = mockEvent(request)

await handler(event)

expect(handleResult).toHaveBeenCalledTimes(1)
expect(https.request).toHaveBeenCalledWith(
new URL(`https://${origin}/${queryStringWithRegion('us')}`),
expect.anything(),
expect.anything(),
)
})

test('Invalid query parameters', async () => {
const queryString = 'apiKey=foo.bar/baz&version=bar.foo/baz&loaderVersion=baz.bar/foo'
const queryStringWithUSRegion =
'?apiKey=foo.bar%2Fbaz&version=bar.foo%2Fbaz&loaderVersion=baz.bar%2Ffoo&ii=fingerprintjs-pro-cloudfront%2F__lambda_func_version__%2Fingress'
const request = mockRequest('/behavior/result', queryString)
request.querystring = `${request.querystring}`
const event = mockEvent(request)

await handler(event)

expect(handleResult).toHaveBeenCalledTimes(1)
expect(https.request).toHaveBeenCalledWith(
new URL(`https://${origin}/${queryStringWithUSRegion}`),
expect.anything(),
expect.anything(),
)
})

test('Suffix with dot', async () => {
const suffix = '.suffix/more/path'
const iiParam = 'ii=fingerprintjs-pro-cloudfront%2F__lambda_func_version__%2Fingress'
const request = mockRequest(`/behavior/result/${suffix}`, '')
const event = mockEvent(request)

await handler(event)

expect(handleResult).toHaveBeenCalledTimes(1)
expect(https.request).toHaveBeenCalledWith(
new URL(`https://${origin}/${suffix}?${iiParam}`),
expect.anything(),
expect.anything(),
)
})

test('Invalid query parameters, GET request', async () => {
const queryString = 'apiKey=foo.bar/baz&version=bar.foo/baz&loaderVersion=baz.bar/foo'
const queryStringWithUSRegion =
'?apiKey=foo.bar%2Fbaz&version=bar.foo%2Fbaz&loaderVersion=baz.bar%2Ffoo&ii=fingerprintjs-pro-cloudfront%2F__lambda_func_version__%2Fingress'
const request = mockRequest('/behavior/result', queryString, 'GET')
request.querystring = `${request.querystring}`
const event = mockEvent(request)

await handler(event)

expect(handleResult).toHaveBeenCalledTimes(1)
expect(https.request).toHaveBeenCalledWith(
new URL(`https://${origin}/${queryStringWithUSRegion}`),
expect.anything(),
expect.anything(),
)
})

test('Suffix with dot, GET request', async () => {
const suffix = '.suffix/more/path'
const iiParam = 'ii=fingerprintjs-pro-cloudfront%2F__lambda_func_version__%2Fingress'
const request = mockRequest(`/behavior/result/${suffix}`, '', 'GET')
const event = mockEvent(request)

await handler(event)

expect(handleResult).toHaveBeenCalledTimes(1)
expect(https.request).toHaveBeenCalledWith(
new URL(`https://${origin}/${suffix}?${iiParam}`),
expect.anything(),
expect.anything(),
)
})

test('Call without suffix', async () => {
const event = mockEvent(mockRequest('/behavior/result'))
await handler(event)
Expand Down
11 changes: 11 additions & 0 deletions proxy/test/utils/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,15 @@ describe('region', () => {
}
expect(getRegion(req, logger)).toBe('eu')
})

test('wrong region', () => {
const req: CloudFrontRequest = {
clientIp: '1.1.1.1',
method: 'GET',
uri: 'fpjs/agent',
querystring: 'apiKey=ujKG34hUYKLJKJ1F&version=3&loaderVersion=3.6.2&region=bar.baz/foo',
headers: {},
}
expect(getRegion(req, logger)).toBe('us')
})
})
7 changes: 6 additions & 1 deletion proxy/utils/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CloudFrontRequest } from 'aws-lambda'
import { Logger } from '../logger'
import { Region } from '../model'

export const getApiKey = (request: CloudFrontRequest, logger: Logger) => getQueryParameter(request, 'apiKey', logger)

Expand All @@ -13,7 +14,11 @@ export const getLoaderVersion = (request: CloudFrontRequest, logger: Logger) =>

export const getRegion = (request: CloudFrontRequest, logger: Logger) => {
const value = getQueryParameter(request, 'region', logger)
return value === undefined ? 'us' : value
if (!value || !(value in Region)) {
return Region.us
}

return value as Region
}

function getQueryParameter(request: CloudFrontRequest, key: string, logger: Logger): string | undefined {
Expand Down

0 comments on commit 006c91b

Please sign in to comment.