Skip to content

Commit 30aa52a

Browse files
Merge pull request #1 from fingerprintjs/feature/agent-js-proxy
JS agent proxy
2 parents 66083a3 + cf3bc90 commit 30aa52a

24 files changed

+580
-114
lines changed

.github/workflows/coverage-diff.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Check coverage for PR
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
run-tests-check-coverage:
8+
runs-on: ubuntu-20.04
9+
name: Run tests & check coverage
10+
steps:
11+
- uses: actions/checkout@v3
12+
- name: Jest coverage comment
13+
id: coverage
14+
uses: ArtiomTr/jest-coverage-report-action@9f733792c44d05327cb371766bf78a5261e43936
15+
with:
16+
package-manager: yarn
17+
output: report-markdown
18+
- name: Read coverage text report
19+
uses: fingerprintjs/action-coverage-report-md@v1
20+
id: coverage-md
21+
with:
22+
srcBasePath: './'
23+
- uses: marocchino/sticky-pull-request-comment@adca94abcaf73c10466a71cc83ae561fd66d1a56
24+
with:
25+
message: |
26+
${{ steps.coverage.outputs.report }}
27+
<details>
28+
<summary>Show full coverage report</summary>
29+
30+
${{ steps.coverage-md.outputs.markdownReport }}
31+
</details>

.github/workflows/coverage-report.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Coverage
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
build-and-run-tests:
10+
runs-on: ubuntu-20.04
11+
name: Build & run tests & publish coverage
12+
steps:
13+
- uses: actions/checkout@v3
14+
15+
- name: Install node
16+
uses: actions/setup-node@v3
17+
with:
18+
node-version-file: '.node-version'
19+
- name: Get yarn cache directory path
20+
id: yarn-cache-dir-path
21+
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
22+
- uses: actions/cache@v3
23+
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
24+
with:
25+
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
26+
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
27+
restore-keys: |
28+
${{ runner.os }}-yarn-
29+
- name: Install Dependencies and prepare packages
30+
run: yarn install
31+
env:
32+
CI: true
33+
- name: Run test
34+
run: yarn test
35+
36+
- name: Create Coverage Badges
37+
uses: jaywcjlove/coverage-badges-cli@e07f25709cd25486855c1ba1b26da53576ff3620
38+
with:
39+
source: coverage/coverage-summary.json
40+
output: coverage/lcov-report/badges.svg
41+
42+
- name: Deploy
43+
uses: JamesIves/github-pages-deploy-action@8817a56e5bfec6e2b08345c81f4d422db53a2cdc
44+
with:
45+
branch: gh-pages
46+
folder: ./coverage/lcov-report/

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ typings/
6969
.yarn-integrity
7070

7171
# dotenv environment variables file
72-
.env.test
72+
.env
7373

7474
# parcel-bundler cache (https://parceljs.org/)
7575
.cache

jest.config.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22
module.exports = {
33
preset: 'ts-jest',
44
testEnvironment: 'node',
5-
testRegex: '/functions/.+test.tsx?$',
5+
testRegex: '/proxy/.+test.tsx?$',
66
passWithNoTests: true,
7-
collectCoverageFrom: ['./functions/**/**.ts', '!**/index.ts'],
7+
collectCoverageFrom: ['./proxy/**/**.ts', '!**/index.ts', '!**/config.ts', './management/**/**.ts'],
88
coverageReporters: ['lcov', 'json-summary', ['text', { file: 'coverage.txt', path: './' }]],
9+
transform: {
10+
'^.+\\.[tj]sx?$': [
11+
'ts-jest',
12+
{
13+
tsconfig: '<rootDir>/tsconfig.test.json',
14+
},
15+
],
16+
},
917
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"lint": "eslint --ext .js,.ts --ignore-path .gitignore --max-warnings 0 .",
1010
"lint:fix": "yarn lint --fix",
1111
"test": "jest --coverage",
12-
"test:dts": "tsc --noEmit --isolatedModules dist/*.d.ts",
12+
"test:dts": "tsc --noEmit --isolatedModules dist/**/*.d.ts",
1313
"emulate-storage": "azurite -l ./storage --silent",
1414
"start": "func start"
1515
},
@@ -31,6 +31,7 @@
3131
"@rollup/plugin-json": "^4.1.0",
3232
"@rollup/plugin-node-resolve": "^15.0.1",
3333
"@rollup/plugin-replace": "^5.0.1",
34+
"@types/jest": "^29.4.1",
3435
"@types/node": "^16.x",
3536
"@typescript-eslint/eslint-plugin": "^5.44.0",
3637
"@typescript-eslint/parser": "^5.44.0",

proxy/config.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { HttpRequest } from '@azure/functions'
2-
import { config } from './config'
1+
import { HttpRequest, Logger } from '@azure/functions'
2+
import { config } from '../utils/config'
33
import * as https from 'https'
4-
import { updateResponseHeaders } from './headers'
4+
import { filterRequestHeaders, updateResponseHeaders } from '../utils/headers'
55
import { HttpResponseSimple } from '@azure/functions/types/http'
66

7-
function getEndpoint(apiKey: string | undefined, version: string, loaderVersion: string | undefined): string {
8-
const lv: string = loaderVersion !== undefined && loaderVersion !== '' ? `/loader_v${loaderVersion}.js` : ''
9-
return `/v${version}/${apiKey}${lv}`
7+
export interface DownloadAgentParams {
8+
httpRequest: HttpRequest
9+
logger: Logger
1010
}
1111

12-
export async function downloadAgent(httpRequest: HttpRequest) {
12+
export async function downloadAgent({ httpRequest, logger }: DownloadAgentParams) {
1313
const apiKey = httpRequest.query.apiKey
1414
const version = httpRequest.query.version
1515
const loaderVersion = httpRequest.query.loaderVersion
@@ -19,26 +19,17 @@ export async function downloadAgent(httpRequest: HttpRequest) {
1919
const url = new URL(`https://${config.fpdcdn}`)
2020
url.pathname = getEndpoint(apiKey, version, loaderVersion)
2121

22-
const headers = {
23-
...httpRequest.headers,
24-
}
22+
logger.verbose('Downloading agent from', url.toString())
2523

26-
// TODO - Extract this into separate function
27-
delete headers['host']
28-
delete headers['content-length']
29-
delete headers['transfer-encoding']
30-
delete headers['via']
24+
const headers = filterRequestHeaders(httpRequest.headers)
3125

32-
return new Promise<HttpResponseSimple & { isRaw?: boolean }>((resolve) => {
26+
return new Promise<HttpResponseSimple>((resolve) => {
3327
const data: any[] = []
3428

35-
console.debug('Downloading agent from', url.toString())
36-
3729
const request = https.request(
3830
url,
3931
{
4032
method: 'GET',
41-
// TODO Filter headers
4233
headers,
4334
},
4435
(response) => {
@@ -53,31 +44,34 @@ export async function downloadAgent(httpRequest: HttpRequest) {
5344

5445
response.on('end', () => {
5546
const body = Buffer.concat(data)
47+
const responseHeaders = updateResponseHeaders(response.headers, domain)
5648

5749
resolve({
5850
status: response.statusCode ? response.statusCode.toString() : '500',
59-
// TODO Filter headers
60-
headers: updateResponseHeaders(response.headers, domain),
51+
headers: responseHeaders,
6152
body: new Uint8Array(body),
62-
isRaw: true,
6353
})
6454
})
6555
},
6656
)
6757

6858
request.on('error', (error) => {
69-
console.error('unable to download agent', { error })
59+
logger.error('unable to download agent', { error })
7060

7161
resolve({
7262
status: '500',
7363
headers: {
74-
'Content-Type': 'application/json',
64+
'Content-Type': 'text/plain',
7565
},
76-
// TODO Generate error response with our integrations format
77-
body: error,
66+
body: 'error',
7867
})
7968
})
8069

8170
request.end()
8271
})
8372
}
73+
74+
function getEndpoint(apiKey: string | undefined, version: string, loaderVersion: string | undefined): string {
75+
const lv: string = loaderVersion !== undefined && loaderVersion !== '' ? `/loader_v${loaderVersion}.js` : ''
76+
return `/v${version}/${apiKey}${lv}`
77+
}

proxy/ingress.ts renamed to proxy/handlers/ingress.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { HttpRequest } from '@azure/functions'
2-
import { config } from './config'
2+
import { config } from '../utils/config'
33
import * as https from 'https'
4-
import { updateResponseHeaders } from './headers'
4+
import { updateResponseHeaders } from '../utils/headers'
55
import { HttpResponseSimple } from '@azure/functions/types/http'
66

77
export function handleIngress(httpRequest: HttpRequest) {

proxy/headers.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

proxy/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import { AzureFunction, Context, HttpRequest } from '@azure/functions'
2-
import { downloadAgent } from './agent'
3-
import { handleIngress } from './ingress'
2+
import { downloadAgent } from './handlers/agent'
3+
import { handleIngress } from './handlers/ingress'
44

55
const httpTrigger: AzureFunction = async (context: Context, req: HttpRequest): Promise<void> => {
6+
context.log.verbose('Handling request', {
7+
req,
8+
context,
9+
})
10+
611
const path = req.params?.restOfPath
712

13+
// TODO Resolve paths using customer variables
814
switch (path) {
915
case 'client': {
10-
context.res = await downloadAgent(req)
16+
context.res = await downloadAgent({ httpRequest: req, logger: context.log })
1117

1218
break
1319
}

0 commit comments

Comments
 (0)