From 35e369fa81094bd3ea0e8a976a585f356d8d9409 Mon Sep 17 00:00:00 2001 From: wajeht <58354193+wajeht@users.noreply.github.com> Date: Sun, 28 Jul 2024 18:23:07 -0500 Subject: [PATCH 1/2] chore: wip --- package-lock.json | 102 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 874310c..c30b986 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "express": "^4.19.2", "express-rate-limit": "^7.3.1", "helmet": "^7.1.0", + "jsonwebtoken": "^9.0.2", "openai": "^4.52.7", "typescript": "^5.5.3" }, @@ -1211,6 +1212,12 @@ "node": ">=8" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -1550,6 +1557,15 @@ "url": "https://dotenvx.com" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2661,6 +2677,49 @@ "license": "MIT", "peer": true }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2704,6 +2763,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2712,6 +2807,12 @@ "license": "MIT", "peer": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -3320,7 +3421,6 @@ "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" diff --git a/package.json b/package.json index cb3ad53..65d9104 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "express": "^4.19.2", "express-rate-limit": "^7.3.1", "helmet": "^7.1.0", + "jsonwebtoken": "^9.0.2", "openai": "^4.52.7", "typescript": "^5.5.3" }, From 7265703991950319ca1c8176cc469af91960846a Mon Sep 17 00:00:00 2001 From: wajeht <58354193+wajeht@users.noreply.github.com> Date: Sun, 28 Jul 2024 18:42:41 -0500 Subject: [PATCH 2/2] feat: Add functionality to handle different user-agent headers in getIndexHandler --- src/handler.test.ts | 46 +++++++++++++++++++++++++++++++++++++++++++-- src/handler.ts | 5 +++++ src/router.test.ts | 4 +++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/handler.test.ts b/src/handler.test.ts index 27f3f48..f25188a 100644 --- a/src/handler.test.ts +++ b/src/handler.test.ts @@ -29,7 +29,11 @@ describe('getHealthzHandler', () => { describe('getIndexHandler', () => { it('should return the commit.sh file with the correct headers', async () => { - const req = {} as Request; + const req = { + headers: { + 'user-agent': 'curl/8.6.0', + }, + } as unknown as Request; const readFileMock = mock.fn<(path: string, encoding: string) => Promise>(() => Promise.resolve('echo "http://localhost"'), @@ -92,7 +96,11 @@ describe('getIndexHandler', () => { }); it('should return the cached commit.sh file if available', async () => { - const req = {} as Request; + const req = { + headers: { + 'user-agent': 'curl/8.6.0', + }, + } as unknown as Request; const readFileMock = mock.fn<(path: string, encoding: string) => Promise>(); const fs = { @@ -149,6 +157,40 @@ describe('getIndexHandler', () => { assert.strictEqual(sendMock.mock.calls.length, 1); assert.strictEqual(sendMock.mock.calls[0].arguments[0], cachedFile); }); + + it('should return a message if the user-agent header does not include "curl"', async () => { + const req = { + headers: { + 'user-agent': 'Mozilla/5.0', + }, + } as unknown as Request; + + const jsonMock = mock.fn<(body: any) => Response>(() => res); + const statusMock = mock.fn<(status: number) => Response>(() => res); + const res = { + status: statusMock, + json: jsonMock, + } as unknown as Response; + + const extractDomainMock = mock.fn<(req: Request) => string>(() => 'http://example.com'); + + const handler = getIndexHandler( + {} as unknown as typeof import('node:fs/promises'), + {} as CacheType, + 'commit.sh', + '/path/to/commit.sh', + extractDomainMock, + ); + await handler(req, res); + + assert.strictEqual(statusMock.mock.calls.length, 1); + assert.strictEqual(statusMock.mock.calls[0].arguments[0], 200); + + assert.strictEqual(jsonMock.mock.calls.length, 1); + assert.deepStrictEqual(jsonMock.mock.calls[0].arguments[0], { + message: "Run this command from your terminal: 'curl -s http://example.com/ | sh'", + }); + }); }); describe('postGenerateCommitMessageHandler', () => { diff --git a/src/handler.ts b/src/handler.ts index 7bc6111..a590c81 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -16,6 +16,11 @@ export function getIndexHandler( extractDomain: (req: Request) => string, ) { return async (req: Request, res: Response) => { + if (!req.headers['user-agent']?.includes('curl')) { + const message = `Run this command from your terminal: 'curl -s ${extractDomain(req)}/ | sh'`; + return res.status(200).json({ message }); + } + let file = cache.get(commitDotShPath); if (!file) { diff --git a/src/router.test.ts b/src/router.test.ts index 9466528..605a582 100644 --- a/src/router.test.ts +++ b/src/router.test.ts @@ -29,7 +29,9 @@ describe('GET /healthz', () => { describe('GET /', () => { it('should return the script with domain replaced', async () => { const readFileMock = mock.method(fs, 'readFile', async () => 'echo "http://localhost"'); - const response = await fetch('http://localhost:3000/'); + const response = await fetch('http://localhost:3000/', { + headers: { 'user-agent': 'curl/8.6.0' }, + }); const body = await response.text(); assert.strictEqual(response.status, 200);