From a48253307c1d31a3858033de0aee7f943ffa20b4 Mon Sep 17 00:00:00 2001 From: Santi Date: Sun, 27 Sep 2020 15:30:48 +0000 Subject: [PATCH] Add support for 'GitLab Token' --- README.md | 1 + package.json | 1 + src/config.ts | 2 ++ src/routes/gitlab/index.ts | 18 +++++++++++++-- test/routes/gitlab/index.spec.ts | 38 ++++++++++++++++++++++++++++++++ yarn.lock | 2 +- 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7879053..169c769 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ We make use of the following environment variables: | NOTIFY_ISSUES_ASSIGNED_TO | A comma-separated list of GitHub user names. Only issues assigned to these users will be notified or leave it empty to receive all notifications. | No | _empty array_ | | IGNORE_PR_OPENED_BY | A comma-separated list of GitHub user names. Only PR not opened by these users will be notified or leave it empty to receive all notifications. | No | _empty array_ | | NOTIFY_CHECK_RUNS_FOR | Comma-separated list of branches to notify Check Runs for. Leave empty to notify for any branch | No | _empty_ _array_ | +| GITLAB_TOKEN | Allows you to configure a secret in order to add a security layer to the webhook | No | _empty_ | ### GitHub Configuration diff --git a/package.json b/package.json index 92289ef..e12f4a9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dev": "nodemon src/index.js" }, "dependencies": { + "@hapi/boom": "^9.1.0", "@hapi/hapi": "^19.1.1", "@hapi/joi": "^17.1.1", "axios": "^0.19.2", diff --git a/src/config.ts b/src/config.ts index 121698c..5cdd648 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,6 +8,7 @@ export interface Config { NOTIFY_CHECK_RUNS_FOR: string[]; NOTIFY_ISSUES_ASSIGNED_TO: string[]; IGNORE_PR_OPENED_BY: string[]; + GITLAB_TOKEN?: string; } export const getConfig = (): Config => { @@ -35,5 +36,6 @@ export const getConfig = (): Config => { NOTIFY_CHECK_RUNS_FOR: process.env['NOTIFY_CHECK_RUNS_FOR']?.split(',') || [], NOTIFY_ISSUES_ASSIGNED_TO: process.env['NOTIFY_ISSUES_ASSIGNED_TO']?.split(',') || [], IGNORE_PR_OPENED_BY: process.env['IGNORE_PR_OPENED_BY']?.split(',') || [], + GITLAB_TOKEN: process.env['GITLAB_TOKEN'], }; }; diff --git a/src/routes/gitlab/index.ts b/src/routes/gitlab/index.ts index f2448ed..6a86738 100644 --- a/src/routes/gitlab/index.ts +++ b/src/routes/gitlab/index.ts @@ -5,6 +5,7 @@ import { TwitchChat } from '../../services/TwitchChat'; import { Config } from '../../config'; import { StreamLabs } from '../../services/StreamLabs'; import { MergeRequestPayload } from '../../schemas/gitlab/merge-request-payload'; +import { Boom, forbidden } from '@hapi/boom'; export const routes = (config: Config): ServerRoute[] => { return [ @@ -15,11 +16,24 @@ export const routes = (config: Config): ServerRoute[] => { headers: gitlabHeader(), }, }, - handler: async (request: Request, h: ResponseToolkit): Promise => { + handler: async (request: Request, h: ResponseToolkit): Promise => { const { headers, payload } = (request as unknown) as { - headers: { 'x-gitlab-event': string }; + headers: { 'x-gitlab-event': string; 'x-gitlab-token': string }; payload: MergeRequestPayload; }; + + if (config.GITLAB_TOKEN) { + if (!headers['x-gitlab-token']) { + console.error("Missing 'X-GitLab-Token' header"); + return forbidden(); + } + + if (config.GITLAB_TOKEN !== headers['x-gitlab-token']) { + console.error("'X-GitLab-Token' mismatch"); + return forbidden(); + } + } + const event = headers['x-gitlab-event']; const twitchChat = new TwitchChat({ diff --git a/test/routes/gitlab/index.spec.ts b/test/routes/gitlab/index.spec.ts index 200304a..750ffb8 100644 --- a/test/routes/gitlab/index.spec.ts +++ b/test/routes/gitlab/index.spec.ts @@ -36,4 +36,42 @@ describe('POST /gitlab', () => { expect(result).toEqual({ message: `Ignoring event: 'test'` }); }); + + describe('with GitLab token configured', () => { + it("rejects any request without the 'X-Gitlab-Token' header", async () => { + const subject = await initServer({ ...getConfig(), GITLAB_TOKEN: 'patatas' }); + + const { statusCode } = await subject.inject({ + method: 'POST', + url: '/gitlab', + headers: { 'X-Gitlab-Event': 'test' }, + }); + + expect(statusCode).toEqual(403); + }); + + it("rejects request with an invalid 'X-Gitlab-Token' header", async () => { + const subject = await initServer({ ...getConfig(), GITLAB_TOKEN: 'patatas' }); + + const { statusCode } = await subject.inject({ + method: 'POST', + url: '/gitlab', + headers: { 'X-Gitlab-Event': 'test', 'X-Gitlab-Token': 'patata' }, + }); + + expect(statusCode).toEqual(403); + }); + + it("accepts request with an valid 'X-Gitlab-Token' header", async () => { + const subject = await initServer({ ...getConfig(), GITLAB_TOKEN: 'patatas' }); + + const { statusCode } = await subject.inject({ + method: 'POST', + url: '/gitlab', + headers: { 'X-Gitlab-Event': 'test', 'X-Gitlab-Token': 'patatas' }, + }); + + expect(statusCode).toEqual(200); + }); + }); }); diff --git a/yarn.lock b/yarn.lock index ac96a02..7171e25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -245,7 +245,7 @@ dependencies: "@hapi/hoek" "9.x.x" -"@hapi/boom@9.x.x", "@hapi/boom@^9.0.0": +"@hapi/boom@9.x.x", "@hapi/boom@^9.0.0", "@hapi/boom@^9.1.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.0.tgz#0d9517657a56ff1e0b42d0aca9da1b37706fec56" integrity sha512-4nZmpp4tXbm162LaZT45P7F7sgiem8dwAh2vHWT6XX24dozNjGMg6BvKCRvtCUcmcXqeMIUqWN8Rc5X8yKuROQ==