From 45a13d443914599f002896ca3e29294ea63cd4e6 Mon Sep 17 00:00:00 2001 From: Steve Cprek Date: Sun, 18 Dec 2022 22:18:20 -0600 Subject: [PATCH 001/123] Add docs for LOG_WITHOUT_NEWLINE --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d5f5a54..5fa31fe 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,14 @@ Will contain a `json` property in the response/output. } } +## No newlines + +You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, + +```bash +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:28 +``` + ## Send an empty response You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, @@ -281,4 +289,4 @@ To create a new image on Docker Hub, I need to create a tag and push it. ## Changelog -See the [changelog](CHANGELOG.md) \ No newline at end of file +See the [changelog](CHANGELOG.md) From 9872755f047fd3d035508f3966e1761e919b1ad8 Mon Sep 17 00:00:00 2001 From: mendhak Date: Mon, 2 Jan 2023 20:53:13 +0000 Subject: [PATCH 002/123] ToC for no newlines --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5fa31fe..677e313 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Please do not use the `:latest` tag as it will break without warning, use a spec - [Disable ExpressJS log lines](#disable-expressjs-log-lines) - [Do not log specific path](#do-not-log-specific-path) - [JSON payloads and JSON output](#json-payloads-and-json-output) +- [No newlines](#no-newlines) - [Send an empty response](#send-an-empty-response) - [Custom status code](#custom-status-code) - [Set response Content-Type](#set-response-content-type) From e466075628f5ae7094bbf141cd3dcc2474535964 Mon Sep 17 00:00:00 2001 From: mendhak Date: Mon, 2 Jan 2023 20:57:48 +0000 Subject: [PATCH 003/123] Ignore build on push for dependabot PRs --- .github/workflows/build.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b004f19..ca8da25 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,13 @@ name: Build # Controls when the action will run. -on: [push, pull_request, workflow_dispatch] +on: + push: + branches-ignore: "dependabot/**" + pull_request: + paths-ignore: + - '**.md' + workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: From 6b70d7953785b9c3790463c482a157c270cb19c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jan 2023 21:09:10 +0000 Subject: [PATCH 004/123] Bump jsonwebtoken from 8.5.1 to 9.0.0 Bumps [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) from 8.5.1 to 9.0.0. - [Release notes](https://github.com/auth0/node-jsonwebtoken/releases) - [Changelog](https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md) - [Commits](https://github.com/auth0/node-jsonwebtoken/compare/v8.5.1...v9.0.0) --- updated-dependencies: - dependency-name: jsonwebtoken dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 162 ++++++++++++++++++---------------------------- package.json | 2 +- 2 files changed, 65 insertions(+), 99 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7dc83b..1bdecc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "concat-stream": "^2.0.0", "express": "^4.17.1", - "jsonwebtoken": "^8.5.0", + "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" }, "engines": { @@ -363,24 +363,18 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "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", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jsonwebtoken/node_modules/ms": { @@ -407,40 +401,21 @@ "safe-buffer": "^5.0.1" } }, - "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==" + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "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==" - }, - "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==" - }, - "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==" - }, - "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==" - }, - "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==" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/media-typer": { "version": "0.3.0", @@ -658,11 +633,17 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { @@ -794,6 +775,11 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } }, "dependencies": { @@ -1070,20 +1056,14 @@ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "requires": { "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", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "dependencies": { "ms": { @@ -1112,40 +1092,18 @@ "safe-buffer": "^5.0.1" } }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "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==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "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==" - }, - "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==" + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "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==" - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } }, "media-typer": { "version": "0.3.0", @@ -1294,9 +1252,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } }, "send": { "version": "0.18.0", @@ -1402,6 +1363,11 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index e5a7cc2..5d82c72 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "dependencies": { "concat-stream": "^2.0.0", "express": "^4.17.1", - "jsonwebtoken": "^8.5.0", + "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" } } From 7af38b76b26387468494ae39a6052cd385e6c933 Mon Sep 17 00:00:00 2001 From: mendhak Date: Mon, 2 Jan 2023 21:43:35 +0000 Subject: [PATCH 005/123] Update badge image to new location Issue https://github.com/badges/shields/issues/8671 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 677e313..5f31769 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![pulls](https://img.shields.io/docker/pulls/mendhak/http-https-echo.svg?style=for-the-badge&logo=docker)](https://hub.docker.com/r/mendhak/http-https-echo) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/mendhak/http-https-echo?color=lightblue&label=latest&sort=semver&style=for-the-badge)](https://hub.docker.com/r/mendhak/http-https-echo) -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/mendhak/docker-http-https-echo/Build?color=darkgreen&style=for-the-badge)](https://github.com/mendhak/docker-http-https-echo/actions?query=workflow%3ABuild) +[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/mendhak/docker-http-https-echo/build.yml?color=darkgreen&style=for-the-badge&branch=master)](https://github.com/mendhak/docker-http-https-echo/actions?query=workflow%3ABuild) From 607129cd577ac44d85700c74b4dac9cf46c13b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=E1=B4=87=CA=80=C9=B4=E1=B4=85=20S=E1=B4=84=CA=9C?= =?UTF-8?q?=E1=B4=8F=CA=80=C9=A2=E1=B4=87=CA=80s?= Date: Thu, 16 Mar 2023 11:06:09 +0100 Subject: [PATCH 006/123] ci: Publish to GHCR, update actions --- .github/workflows/build.yml | 39 ++++++++++++++++++++++------------ .github/workflows/publish.yml | 40 ++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca8da25..b199f08 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,11 +2,12 @@ name: Build -# Controls when the action will run. -on: +# Controls when the action will run. +on: push: - branches-ignore: "dependabot/**" - pull_request: + branches-ignore: + - "dependabot/**" + pull_request: paths-ignore: - '**.md' workflow_dispatch: @@ -21,13 +22,13 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Inspect builder run: | @@ -37,22 +38,34 @@ jobs: echo "Flags: ${{ steps.buildx.outputs.flags }}" echo "Platforms: ${{ steps.buildx.outputs.platforms }}" - - name: Build the image multiplatform - run: docker buildx build --output "type=image,push=false" --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x --tag mendhak/http-https-echo:latest --file ./Dockerfile . + - name: Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: | + mendhak/http-https-echo + + - name: Build the image multi-platform + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + push: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} - name: Build the image single platform and run tests run: ./tests.sh - + - name: Scan the image id: scan - uses: anchore/scan-action@v2 + uses: anchore/scan-action@v3 with: image: "mendhak/http-https-echo:latest" debug: false acs-report-enable: true + - name: upload Anchore scan SARIF report uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{ steps.scan.outputs.sarif }} - - diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c299e82..844e3fd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,14 +11,14 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Inspect builder run: | @@ -28,22 +28,32 @@ jobs: echo "Flags: ${{ steps.buildx.outputs.flags }}" echo "Platforms: ${{ steps.buildx.outputs.platforms }}" - - name: Build the image - run: docker buildx build --output "type=image,push=false" --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x --tag mendhak/http-https-echo:latest --file ./Dockerfile . - - - name: Get the version - id: get_version - run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) - - name: Log in to Docker Hub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - - name: Push to Docker Hub - uses: docker/build-push-action@v2 + - name: Log in to GitHub Container registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: | + mendhak/http-https-echo + ghcr.io/mendhak/http-https-echo + + - name: Build and push image + uses: docker/build-push-action@v4 with: + context: . + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x push: true - tags: mendhak/http-https-echo:${{ steps.get_version.outputs.VERSION }} - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x \ No newline at end of file + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From 2e4e091eb52babee05219493190995ff47fc4c41 Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 16 Mar 2023 20:25:26 +0000 Subject: [PATCH 007/123] Set the severity cutoff for Anchore scan to critical --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b199f08..9d205b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,6 +64,7 @@ jobs: image: "mendhak/http-https-echo:latest" debug: false acs-report-enable: true + severity-cutoff: critical - name: upload Anchore scan SARIF report uses: github/codeql-action/upload-sarif@v2 From af89c2ff007c4768a0d7fa5057420b8be315fbb6 Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 16 Mar 2023 20:51:09 +0000 Subject: [PATCH 008/123] Changelog update v29 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c20fd1..f85c4bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `29` - 2023-03-16 +* Publishing this image to Github Container Registry. Available at `docker pull ghcr.io/mendhak/http-https-echo:latest` + ## Version `28` - 2022-12-02 * Certificate now includes Subject Alternative Names as well as Common Name From f983f580373f51de9df7a7b5ef34af06807ecd69 Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 16 Mar 2023 21:09:23 +0000 Subject: [PATCH 009/123] Update references to version 29 --- README.md | 32 +++++++++++++++++--------------- docker-compose.yml | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5f31769..358a0e5 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,18 @@ - -[`mendhak/http-https-echo`](https://hub.docker.com/r/mendhak/http-https-echo) is a Docker image that can echo various HTTP request properties back to client, as well as in the Docker container logs. -You can use your own certificates, choose your ports, decode JWT headers and filter out certain paths. +`mendhak/http-https-echo` is a Docker image that can echo various HTTP request properties back to client in the response, as well as in the Docker container logs. +It comes with various options that can manipulate the response output, see the table of contents for a full list. ![browser](https://raw.githubusercontent.com/mendhak/docker-http-https-echo/master/screenshots/screenshot.png) -This image is executed as non root by default and is fully compliant with Kubernetes or Openshift deployment. +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:29` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:29` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. +This image is executed as non root by default and is fully compliant with Kubernetes or Openshift deployment. + - [Basic Usage](#basic-usage) - [Choose your ports](#choose-your-ports) @@ -39,7 +41,7 @@ Please do not use the `:latest` tag as it will break without warning, use a spec Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:28 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 Or run with Docker Compose @@ -56,13 +58,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:28 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:29 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:28 + image: mendhak/http-https-echo:29 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -76,7 +78,7 @@ With docker compose, this would be: Use volume mounting to substitute the certificate and private key with your own. This example uses the snakeoil cert. my-http-listener: - image: mendhak/http-https-echo:28 + image: mendhak/http-https-echo:29 ports: - "8080:8080" - "8443:8443" @@ -90,7 +92,7 @@ Use volume mounting to substitute the certificate and private key with your own. If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:28 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:29 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -103,7 +105,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:28 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:29 ## Do not log specific path @@ -111,13 +113,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:28 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:28 + image: mendhak/http-https-echo:29 environment: - LOG_IGNORE_PATH=/ping ports: @@ -148,7 +150,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:28 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 ``` ## Send an empty response @@ -156,7 +158,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:28 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 ``` ## Custom status code @@ -237,7 +239,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:28 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:29 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. diff --git a/docker-compose.yml b/docker-compose.yml index 7932b41..9ade6a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:28 + image: mendhak/http-https-echo:29 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 0c9805d298129d0806ef83a032fb882c93fbc191 Mon Sep 17 00:00:00 2001 From: Marat Abrarov Date: Sat, 3 Jun 2023 00:47:31 +0300 Subject: [PATCH 010/123] Configurable location of SSL certificate and private key files in container. --- README.md | 1 + index.js | 4 ++-- tests.sh | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 358a0e5..b17a516 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Use volume mounting to substitute the certificate and private key with your own. - /etc/ssl/certs/ssl-cert-snakeoil.pem:/app/fullchain.pem - /etc/ssl/private/ssl-cert-snakeoil.key:/app/privkey.pem +`/app/fullchain.pem` and `/app/privkey.pem` paths can be changed - use `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` environment variables to define location of existing certificate and private key inside container. ## Decode JWT header diff --git a/index.js b/index.js index 468bd31..cdd9a14 100644 --- a/index.js +++ b/index.js @@ -121,8 +121,8 @@ app.all('*', (req, res) => { }); let sslOpts = { - key: require('fs').readFileSync('privkey.pem'), - cert: require('fs').readFileSync('fullchain.pem') + key: require('fs').readFileSync(process.env.HTTPS_KEY_FILE || 'privkey.pem'), + cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem') }; //Whether to enable the client certificate feature diff --git a/tests.sh b/tests.sh index 7efdf25..89653b9 100755 --- a/tests.sh +++ b/tests.sh @@ -364,6 +364,39 @@ fi message " Stop containers " docker stop http-echo-tests +message " Check that SSL certificate and private key are loaded from custom location" +cert_common_name="server.example.net" +https_cert_file="$(pwd)/server_fullchain.pem" +https_key_file="$(pwd)/server_privkey.pem" +# Generate a new self signed cert locally +openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout "${https_key_file}" -out "${https_cert_file}" \ + -subj "/CN=${cert_common_name}" \ + -addext "subjectAltName=DNS:${cert_common_name}" +chmod a+r "${https_cert_file}" +chmod a+r "${https_key_file}" +container_https_cert_file="/test/tls.crt" +container_https_key_file="/test/tls.key" +docker run -d --rm \ + -v "${https_cert_file}:${container_https_cert_file}:ro,z" \ + -e HTTPS_CERT_FILE="${container_https_cert_file}" \ + -v "${https_key_file}:${container_https_key_file}:ro,z" \ + -e HTTPS_KEY_FILE="${container_https_key_file}" \ + --name http-echo-tests -p 8443:8443 -t mendhak/http-https-echo +sleep 5 + +REQUEST_WITH_STATUS_CODE="$(curl -s --cacert "$(pwd)/server_fullchain.pem" -o /dev/null -w "%{http_code}" \ + --resolve "${cert_common_name}:8443:127.0.0.1" "https://${cert_common_name}:8443/hello-world")" +if [ "${REQUEST_WITH_STATUS_CODE}" = 200 ] +then + passed "Server certificate and private key are loaded from configured custom location" +else + failed "HTTPS request failed" + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests + message " Check that environment variables returned in response if enabled" docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo sleep 5 From 85e74eb94b7849d5cdc53a4dcf686d0f392440bf Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 3 Jun 2023 10:17:25 +0100 Subject: [PATCH 011/123] Add sleep after docker stop to give time before the next step --- README.md | 6 ++++-- tests.sh | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b17a516..8d43c9d 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,9 @@ With docker compose, this would be: ## Use your own certificates -Use volume mounting to substitute the certificate and private key with your own. This example uses the snakeoil cert. +The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. + +You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: image: mendhak/http-https-echo:29 @@ -86,7 +88,7 @@ Use volume mounting to substitute the certificate and private key with your own. - /etc/ssl/certs/ssl-cert-snakeoil.pem:/app/fullchain.pem - /etc/ssl/private/ssl-cert-snakeoil.key:/app/privkey.pem -`/app/fullchain.pem` and `/app/privkey.pem` paths can be changed - use `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` environment variables to define location of existing certificate and private key inside container. +You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to define the location of existing certificate and private key inside container. ## Decode JWT header diff --git a/tests.sh b/tests.sh index 89653b9..2753f23 100755 --- a/tests.sh +++ b/tests.sh @@ -146,6 +146,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with different internal ports " docker run -d --rm -e HTTP_PORT=8888 -e HTTPS_PORT=9999 --name http-echo-tests -p 8080:8888 -p 8443:9999 -t mendhak/http-https-echo @@ -179,6 +180,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with empty responses " docker run -d --rm -e ECHO_BACK_TO_CLIENT=false --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -195,6 +197,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with response body only " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -212,6 +215,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with JWT_HEADER " docker run -d --rm -e JWT_HEADER=Authentication --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -231,6 +235,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with LOG_IGNORE_PATH " @@ -268,6 +273,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with LOG_WITHOUT_NEWLINE " docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -287,6 +293,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Check that container is running as a NON ROOT USER by default" docker run -d --name http-echo-tests --rm mendhak/http-https-echo @@ -303,6 +310,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Check that container is running as user different that the user defined in image" IMAGE_USER="$(docker image inspect mendhak/http-https-echo -f '{{ .ContainerConfig.User }}')" @@ -323,6 +331,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Check that mTLS server responds with client certificate details" # Generate a new self signed cert locally @@ -363,6 +372,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Check that SSL certificate and private key are loaded from custom location" cert_common_name="server.example.net" @@ -396,6 +406,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Check that environment variables returned in response if enabled" docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -412,6 +423,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Check that environment variables are not present in response by default" docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -428,6 +440,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 popd rm -rf testarea From 31020ab854be45b4225aff8252b1820169f737bf Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 3 Jun 2023 10:36:09 +0100 Subject: [PATCH 012/123] Indicate failing test --- tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.sh b/tests.sh index 2753f23..80163a5 100755 --- a/tests.sh +++ b/tests.sh @@ -400,7 +400,7 @@ if [ "${REQUEST_WITH_STATUS_CODE}" = 200 ] then passed "Server certificate and private key are loaded from configured custom location" else - failed "HTTPS request failed" + failed "Custom certificate location test failed" exit 1 fi From 0e6b2c7c06365d6e6c9fb4051915dd06e11bd568 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 3 Jun 2023 10:46:00 +0100 Subject: [PATCH 013/123] Set version 30 and changelog --- CHANGELOG.md | 3 +++ README.md | 26 +++++++++++++------------- docker-compose.yml | 5 +---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f85c4bd..b1a22c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `30` - 2023-06-03 +* Use `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to specify path to a certificate. + ## Version `29` - 2023-03-16 * Publishing this image to Github Container Registry. Available at `docker pull ghcr.io/mendhak/http-https-echo:latest` diff --git a/README.md b/README.md index 8d43c9d..6a5cdde 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](https://raw.githubusercontent.com/mendhak/docker-http-https-echo/master/screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:29` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:29` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:30` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:30` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -41,7 +41,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 Or run with Docker Compose @@ -58,13 +58,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:29 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:30 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:29 + image: mendhak/http-https-echo:30 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -80,7 +80,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:29 + image: mendhak/http-https-echo:30 ports: - "8080:8080" - "8443:8443" @@ -95,7 +95,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:29 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:30 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -108,7 +108,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:29 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:30 ## Do not log specific path @@ -116,13 +116,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:29 + image: mendhak/http-https-echo:30 environment: - LOG_IGNORE_PATH=/ping ports: @@ -153,7 +153,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 ``` ## Send an empty response @@ -161,7 +161,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:29 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 ``` ## Custom status code @@ -242,7 +242,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:29 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:30 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. diff --git a/docker-compose.yml b/docker-compose.yml index 9ade6a2..03c1ebd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,13 +2,10 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:29 + image: mendhak/http-https-echo:30 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 ports: - "8080:8888" - "8443:9999" - # volumes: - # - /etc/ssl/certs/ssl-cert-snakeoil.pem:/app/fullchain.pem - # - /etc/ssl/private/ssl-cert-snakeoil.key:/app/privkey.pem \ No newline at end of file From a31b45056db79dc2af27af5115ca5c1c4b823456 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 22:11:35 +0000 Subject: [PATCH 014/123] Bump semver from 7.3.8 to 7.5.3 Bumps [semver](https://github.com/npm/node-semver) from 7.3.8 to 7.5.3. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.3.8...v7.5.3) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1bdecc9..4358815 100644 --- a/package-lock.json +++ b/package-lock.json @@ -633,9 +633,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -1252,9 +1252,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "requires": { "lru-cache": "^6.0.0" } From 546b73544cb00954457ed10b6274b25e2bdefad5 Mon Sep 17 00:00:00 2001 From: Ricardo Vega Date: Sun, 3 Sep 2023 03:44:25 +0200 Subject: [PATCH 015/123] ISSUE-56 Add middleware for prometheus metrics --- README.md | 53 +++++++++++++++++++++++++++++--------------- docker-compose.yml | 8 +++++-- index.js | 55 +++++++++++++++++++++++++++++++--------------- package.json | 3 ++- tests.sh | 31 +++++++++++++++++++++----- 5 files changed, 105 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 6a5cdde..838e247 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,12 @@ [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/mendhak/docker-http-https-echo/build.yml?color=darkgreen&style=for-the-badge&branch=master)](https://github.com/mendhak/docker-http-https-echo/actions?query=workflow%3ABuild) - `mendhak/http-https-echo` is a Docker image that can echo various HTTP request properties back to client in the response, as well as in the Docker container logs. It comes with various options that can manipulate the response output, see the table of contents for a full list. ![browser](https://raw.githubusercontent.com/mendhak/docker-http-https-echo/master/screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:30` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:30` The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:30` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -31,8 +30,11 @@ This image is executed as non root by default and is fully compliant with Kubern - [Add a delay before response](#add-a-delay-before-response) - [Only return body in the response](#only-return-body-in-the-response) - [Include environment variables in the response](#include-environment-variables-in-the-response) -- [Client certificate details (mTLS) in the response](#client-certificate-details--mtls--in-the-response) +- [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) +- [Prometheus Metrics](#prometheus-metrics) - [Output](#output) + - [Curl output](#curl-output) + - [`docker logs` output](#docker-logs-output) - [Building](#building) - [Changelog](#changelog) @@ -75,9 +77,9 @@ With docker compose, this would be: ## Use your own certificates -The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. +The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. -You can use volume mounting to substitute the certificate and private key with your own. +You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: image: mendhak/http-https-echo:30 @@ -166,7 +168,7 @@ docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendha ## Custom status code -Use `x-set-response-status-code` to set a custom status code. +Use `x-set-response-status-code` to set a custom status code. You can send it as a header: @@ -188,7 +190,7 @@ That will cause the reponse status code to be: ## Set response Content-Type -Use `x-set-response-content-type` to set the Content-Type of the response. +Use `x-set-response-content-type` to set the Content-Type of the response. You can send it as a header: @@ -211,7 +213,7 @@ This will cause the response content type to be: ## Add a delay before response -Use `x-set-response-delay-ms` to set a custom delay in milliseconds. This will allow you to simulate slow responses. +Use `x-set-response-delay-ms` to set a custom delay in milliseconds. This will allow you to simulate slow responses. You can send it as a header: @@ -219,7 +221,7 @@ You can send it as a header: curl -v -H "x-set-response-delay-ms: 6000" http://localhost:8080/ ``` -You can send it as a querystring parameter: +You can send it as a querystring parameter: ```bash curl -v http://localhost:8080/some/path?x-set-response-delay-ms=6000 @@ -227,45 +229,60 @@ curl -v http://localhost:8080/some/path?x-set-response-delay-ms=6000 ## Only return body in the response -Use the querystring parameter, `response_body_only=true` to get just the request body in the response, none of the associated metadata. +Use the querystring parameter, `response_body_only=true` to get just the request body in the response, none of the associated metadata. ```bash curl -s -k -X POST -d 'cauliflower' http://localhost:8080/a/b/c?response_body_only=true ``` -The output will be 'cauliflower'. +The output will be 'cauliflower'. ## Include environment variables in the response -You can have environment variables (that are visible to the echo server's process) added to the response body. Because this could contain sensitive information, it is not a default behavior. +You can have environment variables (that are visible to the echo server's process) added to the response body. Because this could contain sensitive information, it is not a default behavior. -Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. +Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:30 ``` -Then do a normal request via curl or browser, and you will see the `env` property in the response body. +Then do a normal request via curl or browser, and you will see the `env` property in the response body. ## Client certificate details (mTLS) in the response -To get client certificate details in the response body, start the container with `MTLS_ENABLE=1` environment variable. When passing a client certificate, the details about that certificate can be echoed back in the response body. The client certificate will not be validated. +To get client certificate details in the response body, start the container with `MTLS_ENABLE=1` environment variable. When passing a client certificate, the details about that certificate can be echoed back in the response body. The client certificate will not be validated. -For example, invoke using curl, passing a certificate and key. +For example, invoke using curl, passing a certificate and key. ```bash curl -k --cert cert.pem --key privkey.pem https://localhost:8443/ ``` -The response body will contain details about the client certificate passed in. +The response body will contain details about the client certificate passed in. -If you browse to https://localhost:8443/ in Firefox, you won't get prompted to supply a client certificate unless you have [an imported certificate by the same issuer as the server](https://superuser.com/questions/1043415/firefox-doesnt-ask-me-for-a-certificate-when-visiting-a-site-that-needs-one). If you need browser prompting to work, you'll need to follow the 'use your own certificates' section. Firefox needs the imported certificate to be in a PKCS12 format, so if you have a certificate and key already, you can combine them using +If you browse to https://localhost:8443/ in Firefox, you won't get prompted to supply a client certificate unless you have [an imported certificate by the same issuer as the server](https://superuser.com/questions/1043415/firefox-doesnt-ask-me-for-a-certificate-when-visiting-a-site-that-needs-one). If you need browser prompting to work, you'll need to follow the 'use your own certificates' section. Firefox needs the imported certificate to be in a PKCS12 format, so if you have a certificate and key already, you can combine them using ```bash openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx ``` +## Prometheus Metrics + +By default the server uses `express-prom-bundle` middleware to expose http performance +metrics in `/metrics`. +You can configure these metrics using the following variables: + +| Variable | Description | Default Value | +| -------- | ----------- | ------------- | +| PROMETHEUS_DISABLED | Toggles off the prometheus middleware | false | +| PROMETHEUS_WITH_PATH | Partitions the metrics by the requested path | false | +| PROMETHEUS_WITH_METHOD | Partitions the metrics by HTTP method | true | +| PROMETHEUS_WITH_STATUS | Partitions the metrics by HTTP status | true | +| PROMETHEUS_METRIC_TYPE | Sets the type of metric, histogram or summary | summary | + +> Please check the middleware [documentation](https://github.com/jochen-schweizer/express-prom-bundle#options) for more details. ## Output diff --git a/docker-compose.yml b/docker-compose.yml index 03c1ebd..b437e79 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,15 @@ version: '3' services: - my-http-listener: image: mendhak/http-https-echo:30 - environment: + environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 + - PROMETHEUS_DISABLED=false + - PROMETHEUS_WITH_PATH=false + - PROMETHEUS_WITH_METHOD=true + - PROMETHEUS_WITH_STATUS=true + - PROMETHEUS_METRIC_TYPE=summary ports: - "8080:8888" - "8443:9999" diff --git a/index.js b/index.js index cdd9a14..454b95a 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,35 @@ -var express = require('express') -const morgan = require('morgan'); -var http = require('http') -var https = require('https') -var app = express() const os = require('os'); const jwt = require('jsonwebtoken'); -var concat = require('concat-stream'); +const http = require('http') +const https = require('https') +const morgan = require('morgan'); +const express = require('express') +const concat = require('concat-stream'); const { promisify } = require('util'); +const promBundle = require("express-prom-bundle"); + +const { + PROMETHEUS_DISABLED = false, + PROMETHEUS_WITH_PATH = false, + PROMETHEUS_WITH_METHOD = 'true', + PROMETHEUS_WITH_STATUS = 'true', + PROMETHEUS_METRIC_TYPE = 'summary', +} = process.env + const sleep = promisify(setTimeout); +const metricsMiddleware = promBundle({ + includePath: (PROMETHEUS_WITH_PATH == 'true'), + includeMethod: (PROMETHEUS_WITH_METHOD == 'true'), + includeStatusCode: (PROMETHEUS_WITH_STATUS == 'true'), + metricType: PROMETHEUS_METRIC_TYPE, +}); +const app = express() app.set('json spaces', 2); app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); +if(PROMETHEUS_DISABLED !== 'true') { + app.use(metricsMiddleware); +} if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ app.use(morgan('combined')); @@ -48,11 +67,11 @@ app.all('*', (req, res) => { }; //Add client certificate details to the output, if present - //This only works if `requestCert` is true when starting the server. + //This only works if `requestCert` is true when starting the server. if(req.socket.getPeerCertificate){ echo.clientCertificate = req.socket.getPeerCertificate(); } - + //Include visible environment variables if(process.env.ECHO_INCLUDE_ENV_VARS){ echo.env = process.env; @@ -91,15 +110,15 @@ app.all('*', (req, res) => { if(setResponseContentType){ res.contentType(setResponseContentType); } - + //Ability to send an empty response back if (process.env.ECHO_BACK_TO_CLIENT != undefined && process.env.ECHO_BACK_TO_CLIENT == "false"){ res.end(); - } + } //Ability to send just the request body in the response, nothing else else if ("response_body_only" in req.query && req.query["response_body_only"] == "true") { res.send(req.body); - } + } //Normal behavior, send everything back else { res.json(echo); @@ -107,17 +126,17 @@ app.all('*', (req, res) => { //Certain paths can be ignored in the container logs, useful to reduce noise from healthchecks if (process.env.LOG_IGNORE_PATH != req.path) { - + let spacer = 4; if(process.env.LOG_WITHOUT_NEWLINE){ spacer = null; } - + console.log(JSON.stringify(echo, null, spacer)); } }); - + }); let sslOpts = { @@ -127,10 +146,10 @@ let sslOpts = { //Whether to enable the client certificate feature if(process.env.MTLS_ENABLE){ - sslOpts = { - requestCert: true, - rejectUnauthorized: false, - ...sslOpts + sslOpts = { + requestCert: true, + rejectUnauthorized: false, + ...sslOpts } } diff --git a/package.json b/package.json index 5d82c72..19c2643 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "concat-stream": "^2.0.0", "express": "^4.17.1", "jsonwebtoken": "^9.0.0", - "morgan": "^1.10.0" + "morgan": "^1.10.0", + "express-prom-bundle": "^6.6.0" } } diff --git a/tests.sh b/tests.sh index 80163a5..7526c2d 100755 --- a/tests.sh +++ b/tests.sh @@ -95,27 +95,27 @@ fi REQUEST_WITH_SLEEP_MS=$(curl -o /dev/null -Ss -H "x-set-response-delay-ms: 6000" -k https://localhost:8443/ -w '%{time_total}') -if [[ $(echo "$REQUEST_WITH_SLEEP_MS>5" | bc -l) == 1 ]]; then +if [[ $(echo "$REQUEST_WITH_SLEEP_MS>5" | bc -l) == 1 ]]; then passed "Request header with response delay passed" -else +else failed "Request header with response delay failed" echo $REQUEST_WITH_SLEEP_MS exit 1 fi REQUEST_WITH_SLEEP_MS=$(curl -o /dev/null -Ss -k https://localhost:8443/sleep/test?x-set-response-delay-ms=5000 -w '%{time_total}') -if [[ $(echo "$REQUEST_WITH_SLEEP_MS>4" | bc -l) == 1 ]]; then +if [[ $(echo "$REQUEST_WITH_SLEEP_MS>4" | bc -l) == 1 ]]; then passed "Request query with response delay passed" -else +else failed "Request query with response delay failed" echo $REQUEST_WITH_SLEEP_MS exit 1 fi REQUEST_WITH_INVALID_SLEEP_MS=$(curl -o /dev/null -Ss -H "x-set-response-delay-ms: XXXX" -k https://localhost:8443/ -w '%{time_total}') -if [[ $(echo "$REQUEST_WITH_INVALID_SLEEP_MS<2" | bc -l) == 1 ]]; then +if [[ $(echo "$REQUEST_WITH_INVALID_SLEEP_MS<2" | bc -l) == 1 ]]; then passed "Request with invalid response delay passed" -else +else failed "Request with invalid response delay failed" echo $REQUEST_WITH_INVALID_SLEEP_MS exit 1 @@ -442,6 +442,25 @@ message " Stop containers " docker stop http-echo-tests sleep 5 +message " Start container with PROMETHEUS " +docker run -d --rm -e --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +sleep 5 +curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null +METRICS_CHECK="$(curl -sk http://localhost:8080/metrics | grep http_request_duration_seconds_count | grep GET | cut -d' ' -f2)" + +if [ "$METRICS_CHECK" == "1" ] +then + passed "PROMETHEUS metrics are working" +else + failed "PROMETHEUS metrics are not working" + docker logs http-echo-tests + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + popd rm -rf testarea message "DONE" From c4fe9fcc44fa1b693affdcea6d462c67ee883739 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 14:01:54 +0000 Subject: [PATCH 016/123] Prometheus disabled by default --- README.md | 19 ++++++++++--------- docker-compose.yml | 3 ++- index.js | 7 +++++-- tests.sh | 36 +++++++++++++++++++++++++++++------- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 838e247..e595037 100644 --- a/README.md +++ b/README.md @@ -270,17 +270,18 @@ openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx ## Prometheus Metrics -By default the server uses `express-prom-bundle` middleware to expose http performance -metrics in `/metrics`. +To expose http performance metrics, set the `PROMETHEUS_ENABLED` environment variable to true, the metrics will be available at `/metrics`. This uses the [`express-prom-bundle`](https://github.com/jochen-schweizer/express-prom-bundle) middleware + You can configure these metrics using the following variables: -| Variable | Description | Default Value | -| -------- | ----------- | ------------- | -| PROMETHEUS_DISABLED | Toggles off the prometheus middleware | false | -| PROMETHEUS_WITH_PATH | Partitions the metrics by the requested path | false | -| PROMETHEUS_WITH_METHOD | Partitions the metrics by HTTP method | true | -| PROMETHEUS_WITH_STATUS | Partitions the metrics by HTTP status | true | -| PROMETHEUS_METRIC_TYPE | Sets the type of metric, histogram or summary | summary | +| Variable | Description | Default Value | +| ----------------------- | --------------------------------------------- | ------------- | +| PROMETHEUS_ENABLED | Toggles on the prometheus middleware | false | +| PROMETHEUS_METRICS_PATH | The path at which the metrics will be visible | /metrics | +| PROMETHEUS_WITH_PATH | Partitions the metrics by the requested path | false | +| PROMETHEUS_WITH_METHOD | Partitions the metrics by HTTP method | true | +| PROMETHEUS_WITH_STATUS | Partitions the metrics by HTTP status | true | +| PROMETHEUS_METRIC_TYPE | Sets the type of metric, histogram or summary | summary | > Please check the middleware [documentation](https://github.com/jochen-schweizer/express-prom-bundle#options) for more details. diff --git a/docker-compose.yml b/docker-compose.yml index b437e79..09a948b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,8 @@ services: environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 - - PROMETHEUS_DISABLED=false + - PROMETHEUS_ENABLED=true + - PROMETHEUS_METRICS_PATH=/metrics - PROMETHEUS_WITH_PATH=false - PROMETHEUS_WITH_METHOD=true - PROMETHEUS_WITH_STATUS=true diff --git a/index.js b/index.js index 454b95a..03391c1 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,8 @@ const { promisify } = require('util'); const promBundle = require("express-prom-bundle"); const { - PROMETHEUS_DISABLED = false, + PROMETHEUS_ENABLED = false, + PROMETHEUS_METRICS_PATH = '/metrics', PROMETHEUS_WITH_PATH = false, PROMETHEUS_WITH_METHOD = 'true', PROMETHEUS_WITH_STATUS = 'true', @@ -18,6 +19,7 @@ const { const sleep = promisify(setTimeout); const metricsMiddleware = promBundle({ + metricsPath: PROMETHEUS_METRICS_PATH, includePath: (PROMETHEUS_WITH_PATH == 'true'), includeMethod: (PROMETHEUS_WITH_METHOD == 'true'), includeStatusCode: (PROMETHEUS_WITH_STATUS == 'true'), @@ -27,7 +29,8 @@ const metricsMiddleware = promBundle({ const app = express() app.set('json spaces', 2); app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); -if(PROMETHEUS_DISABLED !== 'true') { + +if(PROMETHEUS_ENABLED === 'true') { app.use(metricsMiddleware); } diff --git a/tests.sh b/tests.sh index 7526c2d..0dbd4f5 100755 --- a/tests.sh +++ b/tests.sh @@ -256,6 +256,7 @@ fi message " Stop containers " docker stop http-echo-tests +sleep 5 message " Start container with DISABLE_REQUEST_LOGS " docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo @@ -442,18 +443,39 @@ message " Stop containers " docker stop http-echo-tests sleep 5 -message " Start container with PROMETHEUS " -docker run -d --rm -e --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +message " Start container with PROMETHEUS disabled " +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo sleep 5 curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null -METRICS_CHECK="$(curl -sk http://localhost:8080/metrics | grep http_request_duration_seconds_count | grep GET | cut -d' ' -f2)" -if [ "$METRICS_CHECK" == "1" ] +# grep for http_request_duration_seconds_count ensure it is not present at /metric path + +METRICS_CHECK="$(curl -sk http://localhost:8080/metrics | grep -v http_request_duration_seconds_count )" + +if [[ "$METRICS_CHECK" == *"http_request_duration_seconds_count"* ]] then - passed "PROMETHEUS metrics are working" + failed "PROMETHEUS metrics are enabled" + exit 1 else - failed "PROMETHEUS metrics are not working" - docker logs http-echo-tests + passed "PROMETHEUS metrics are disabled by default" +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + +message " Start container with PROMETHEUS enabled " +docker run -d -e PROMETHEUS_ENABLED=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +sleep 5 +curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null + +METRICS_CHECK="$(curl -sk http://localhost:8080/metrics | grep http_request_duration_seconds_count )" + +if [[ "$METRICS_CHECK" == *"http_request_duration_seconds_count"* ]] +then + passed "PROMETHEUS metrics are enabled" +else + failed "PROMETHEUS metrics are disabled" exit 1 fi From 32592cbcc3b4736274e7d8ff5766b231d2d8546f Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 18:07:04 +0000 Subject: [PATCH 017/123] Remove s390x platform build, because of qemu bug Issue: https://github.com/nodejs/docker-node/issues/1973 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9d205b3..1922fb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: uses: docker/build-push-action@v4 with: context: . - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le push: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 3466972edb3e00b568b518902eb6360219bea72b Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 18:07:58 +0000 Subject: [PATCH 018/123] Remove s390x build --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 844e3fd..a8112f3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,7 +53,7 @@ jobs: uses: docker/build-push-action@v4 with: context: . - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From b84cbb3819ddab1fe357fbade24d32349c42e34d Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 18:34:05 +0000 Subject: [PATCH 019/123] Don't auto update the ToC --- .vscode/settings.json | 3 +++ README.md | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5f3108a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "markdown.extension.toc.updateOnSave": false +} \ No newline at end of file diff --git a/README.md b/README.md index e595037..7879345 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ This image is executed as non root by default and is fully compliant with Kubern - [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) - [Prometheus Metrics](#prometheus-metrics) - [Output](#output) - - [Curl output](#curl-output) - - [`docker logs` output](#docker-logs-output) - [Building](#building) - [Changelog](#changelog) From 22df117953053e3c7b3755722a957838ab115484 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 18:59:35 +0000 Subject: [PATCH 020/123] Update screenshots --- README.md | 10 +++++----- screenshots/screenshot.png | Bin 59182 -> 102642 bytes screenshots/screenshot2.png | Bin 29275 -> 60286 bytes screenshots/screenshot3.png | Bin 99199 -> 183010 bytes 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7879345..2b75ccb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ `mendhak/http-https-echo` is a Docker image that can echo various HTTP request properties back to client in the response, as well as in the Docker container logs. It comes with various options that can manipulate the response output, see the table of contents for a full list. -![browser](https://raw.githubusercontent.com/mendhak/docker-http-https-echo/master/screenshots/screenshot.png) +![browser](./screenshots/screenshot.png) The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:30` The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:30` @@ -32,7 +32,7 @@ This image is executed as non root by default and is fully compliant with Kubern - [Include environment variables in the response](#include-environment-variables-in-the-response) - [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) - [Prometheus Metrics](#prometheus-metrics) -- [Output](#output) +- [Screenshots](#screenshots) - [Building](#building) - [Changelog](#changelog) @@ -283,15 +283,15 @@ You can configure these metrics using the following variables: > Please check the middleware [documentation](https://github.com/jochen-schweizer/express-prom-bundle#options) for more details. -## Output +## Screenshots #### Curl output -![curl](https://raw.githubusercontent.com/mendhak/docker-http-https-echo/master/screenshots/screenshot2.png) +![curl](./screenshots/screenshot2.png) #### `docker logs` output -![dockerlogs](https://raw.githubusercontent.com/mendhak/docker-http-https-echo/master/screenshots/screenshot3.png) +![dockerlogs](./screenshots/screenshot3.png) diff --git a/screenshots/screenshot.png b/screenshots/screenshot.png index 902a612808f5f12118246dbd1ab7594e9bd03e8f..fa5c95e3f505dcf29c5b68b21f02ee7b01d26161 100644 GIT binary patch literal 102642 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%0A`>(82eYWN=HU4I$l|&KjaQq`MoDAO;Zz`_Hm1X6 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%0DhQ_e6wYU;42Q=XI@sABT=@^!=UWXwdqI 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⋙#BR z@@_Wt4s0MBT=l3TQ^RFyq$X5Zb22#zysx+A&}>YbwP;R|Bz)s$Zb*ym+VpcJp9_&0 zlXaa^$P10eQm=%dpmkK)6n>w4hnF@aap*MH^s$Mom*Uz+ z43`y&+$(6&z5(`a@HXKOrPMXAmEn)56>NFp9J8L^re-qJ*=h3k#SQO1$n@O?5a>T? zoT_F1_5|_4GzurT6OndMb3OR7qR+`AqmZoCe(LE3u;=(}myi&a2hFu<%Ud;UEfj$Q z*ILY{XpQpgdpl~M;8R5XnYN}0Z-L0ZMH=@TeegDgNiECSgTQOmlmr4F4hrJr=!!iY zeF96q`KPx|fk!Btq^BC25qAVbu1k>f-c{-6s`|Lfe&eOQwjKflgrGk+v|KOVfAl@- bji&1n9(*G@-%O2h`H`1VeqQ$MZNR?)Q65t= literal 59182 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

EvLCsma1R|0iinLTHaGxc^=+?$uNY=bhzpE^ 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

kYEhm#B6ZQ4$gj)^lHNv-0|-D@dhtEBt_&lSEOc zd^JTcrBVI!SE?M$yDu$rRSl$`#7{Q&#S3?mp^iRN=rM`y#s@~;d7Dr{95%Mch@!6nWv0Rl;6QG zxyr_SFwg>PCB)f)t1G5o!J>i+H}1Yf0iB5G3ubT97RlRgv{I$}D{0{K?|F5VSm(-G zk)1PKBsqZw=By?}d%2=tP**}%)BXrprqo7SAea{VboYCUaQ?;M3|cBafK|sy$cL9JM{K?D8AW{)Ye9$e*od1A)wvy9GB`AK?>2An`iM z0`4b9E@4(!YsOB)E&c|VeqOwjidDjkq(?{YO^`efS7jdg>H_5>Ic&nN_sa7 z!;wpJ&@9xFd%h7ohL$528R8{V!#$#6uUf}=OtqpDZ@6)yD>ED-VY#ZW@i5CxBiBgU zkvc=0*1`Yj)khx&yR(pfv+BD1DdEp|2Iq3W7w~Z(Gofc-=P(EVuQC%38w@j|y0BGZ zD}GLLWatnZBX)LUM=-mQgL!`?CsA)wqxnH!AjLbm;wF5xlo52hA$Rm>`lu1(v-jdu zx*PHj^RCJ{vESO|tLxn}F>rL%Lho#k5hbwmpbPBkFkBDartq5t&BQ<3*BR7D?Nn7b zbR$Y$RGTEo=P=t43$5H+zlrd_BCdy+NW#FI)Yndp#3bo6FaFAR6=4S$|EOIa-O1>o z|EH(LOiTWj;0p*TGQcq9m6>VGX7DHR0I{f&KoDs-0p*84{hwIm*onWE;pev#jU0H> z5>TVzcQv5f(Cn*~``y=->oSOjv(aikBxEp^5(_rHgmf0$VDmE^AF{$%g^PjJm4v>2 z*wvwMH3vMhR+ajbD_m&M03BKZp1awIh z+Ex$G43|cbK;Blm`P>h0KAN5>CylI17!%1-` z4YN=R_z7fGcdsNq6$*ZNsYdR^SB5dIzcIknpad;27^$SZzJp;UE?zBeO~h_2P%f}w zlf(Z3u+GxrI=RDazGVSOpA=ZkZSlyD`cTo?>l1<`ke35*mh*x<2FESiHTey6?*a-) zUbpe&sTm%4i6<2rH@{B9*>w28=w6d7_*cIlsj}0K#Y@FZjXfF3l9IK~iqRb!VM4NP zv?(7J6hyn~ocu+Bj64f7NEd`Hb!v{j;N#q0$;tKz0vvXL zDkiH=l`E(B{!OEliW&b?Xbt>7h1P$&s7@A|6HzXdv6p6Z)XBr(laBPxvn#6GAL(`J zqtc$DSpAd(UnLc9@-3$f6qAP%{U9V}0iVCsM)fmjcxz%sR0@anv-oG7{hiN~H&@TDQfDO@2K)FDe;0wt@*0TS*pTfDC%FA4kx3zM#4=cdzP=i4m-dvR zWR@xMiH6{TuAt~a63)f-TG#!%ay;!{wd$^DztKazKSFw~``m8VN}Sy#{?28AXxsz= zV_(v{A!Hi)c=`*Uqe6T{C0mAA>~ngbhEOgt z?V7E<^7{i@C#s7fw|R2)W+{h({5bNyzyNq7LT79qFQ>R|ZqF>p&^Nf8n@IXDJuF5j zW8R#C!4&KM=mH9B6=#gw4uJh8$<5GhT{YyW7VvX0abUJ{WnHSgw(`1)r{IHO_`^VOV`T#9L& zifQ1nz$trWE-Jr*O^h_iLl0HwvANgUF?!TJTB}Y_0u)f*TOQL>ua6R(486PLC%AYx zV4tJrxa_l!HQ6;9{LzJZjzMBhDRg(4Le9yxhZ+FgBy5XKfmM?9-M>rd5jNcU*gmL1 zGs6q7NpVY>1>b+&S_O17P9BGn7W^q8ewyNaI>t<--PzMFdht26IHAz}m4({Oo+l%Z z2*c`%<{v*ngb{9Psq)}~@lH>IwvGfI*sL_{oWknFM-%GDWqq5VeYM-wiF>qs5adbf z)TmhQ#{9cOFPgi77JnGwl60&i zlL1=`bycCD;bB8$+qg4Z?;`+_%{#7KN4u%r=FEFDWo4DpZ}uK&RhI)_FrjM%O8+`&Rk=Z=Aey(ow00X>ANm2W${ zqfrO8D8ODd$wjaNxkFrLgr{n5j$P76h1WM52w71rEX}+!7+1}32TR&+;RM=Gvp-*e zbw3=NxPaX7-v5^B4w5L}>FOBW#ZR^Mj=_7 zbMUi&;(G6H8B+_t$x1ea*7a(VYJHq>j#%CcsYPULA}ZhZvPbqnfn-fi@KTfI53Pxu z@BJNXaMfjBPt4P81B+ATSRQGZNy3k>665*X2C0VbME$H+F>P`fbY?M1hsq1JU(NP< zoQW@hrnyzk&=C9qo-hL!df(eF-4%7GssuQ6!LIr}LI0D0Xi!Y{w>)e*lb!W->n=hz zY&v!B6jQi^2&Yg=dl>!+v;W)46*-t_hCh`=0GK!a067hYMi8PjaWHb2BRFYsHoDT=-rZo3W0Fpp))Y`(C24{D&?$Aa z3^k^-JiP|Y=Wqo9`()Wy06pyUe9QZ$Cn7|~wAdcC#VK|R+5!gTM2Nv>?Ac3LXaf0> zBSp~nm~bujb3XL^W1oq?!KLcix#F8TRH zXy%M(FV~cyPQE$OHqr*?P=$8%xI-DC7fyCD%wy&sdDXKKI4qo8 zZbC{{d@X9c;^heOjubOB0$^h-)J%ut8SloAr&m2rVXhm!WrM5=uhR!%n;ysgxpgG= zx$jhYnd&h7KHtSk#R(LZIn)Ux;o?N#7ytOyAzP-%j61ZLMBN3p?~wr@pngiQdj&7s z;qU=%==$DA2s#X2#EOM(b7t$rl(LT#D2LdlJyUU0iMv9_;}Hu$OC=x6WvBfsi^ITz zXV|d!Ik^#jHm*YaQ080-gApyRDec2K_L)S>Xkwuui^1_F2O(g5?qo~09eh4?T#7qOlml#Ycs`Xz?NuKR zi{!1}{&syyY4YPB(2sg?^QYJI6cWg;tkb%W?F@5ddLDWY;fAK!jdudOhkF^lZ~bAO zYRN@wSdx7UVo%P7aE^s&JePaTF&cV1S;FxqS3qt?YbG~!&y}Bv6`uuceWj2wZYYS> zbhXbuu0K;iZLeR$CJoQJe<(D+{>LZ}tsN!(A7au!`Qg8_o;MbI(By`MtGDm(_-|@o z9<;N-GHzX=Op+h`^6N7?bUi4(ndR+oHQ++=rU5Y^Jko%tuZi;h2e&PNj36dw7I?Ok zt|U=Uj!Lloh%A)oC?o6P8ztLQv$;lzub({wmY&yCT;$C%t(qjIH`_3?;t0Nx&jIRT zAj*As2B zlDNqdr(8I5L}TWJQ=P9)Pzz<1pD5s3#{Mg|M-HAj*-0$kUHG*LJjkhLj(|h#Yy|e~ zU&jE1@td6mY(x;i{@!xQ=;#csWLGPZ^tbUR?c5J^^A|X$Tc=k?C(1wA9Y6Sey1VgW zT6+-%SSHfuqK8bbqJC^3+&_C&^926+h3Uz!O<`;u2loNJ)z&+} zMwU&^(J!Pwuu*Y-`VU*IL7aATT@k(vRjiU4(>F!_G|ZO?#LHVQb7IPVV#nDge(JeW z{R>QMw2f7jr`tbM>wJOp5gu+?LVcgKcn=pPXS<-*z4l6ROl-5?cZ2B{c8=fA3dC-z z2{ouW`=$+O#w?mlTvH>?-#&2sWJf306BKGFIMa0P?W9@HJ@PyQ#11ZkwK23N5M8rc z%#Cv&$Z0`!D$qkIslQ2lD__+>VfEO)>^c)LF#dS_HsNZ1dzt|`GE^~a4Ik}s%o-Qf zgE9@XeGTOev6D+pFLxlH&_^p2#Jy|_^1XNX@<(suF;y(HVlt~5<2~=4+ev}d7FT`F zDFH4;xXD~BK)?)*S~;eYfu&)L1FW@s40-!H0 z`|Y{~ibrZhTTEyLqMQPW%NeGB_xMS~m&K9$d+iBiXXTxqv6B8RyZV|+_eQ0-4}jJ$ zCw|7`{Jdkha}A*t!XQB7qV*{Lj0@m07Wf=up~I$H_mUjfzng^-Wg&aFD9PRz1&5Sg z-}l}dUR8CtmB}0f&p~DJH9CnhTg+!vNq_g`pQ*6RzmLh~*+WmJx7kmNNwZAxo9TPV z{L?y!Dsu^o9lV9&c-SYSnP&C~F;bm8>T59@DZ-sU0a4|dp`;n>Boboivg{S(K;t~b z^2y&PV~cq-l=7BOJ0k0?nVqs+?#fxMqkA%6Uujh>u#L`?P74-k7z8PPnGp#};o)7t ziH~q0*E0!BpL`!Qao#DdGIiJuHQB=9Vdrqms#Dr}6N0>ToqzhsCqV9zDyKF9h6fWc zfBGR@dihL!)(jh+N}?pyzl7HlHwiAD4+7{~_{<$PxK&#;0V3(c@qrHuh>+LDftYkC|3bTN82&K+w@CCa)jNDrqTXLIdvFnhTDa27 zX4}vMYZ>)n+?S7-y_%3yU<^X_Jq9<-vU}WjKg-c5b(T>rItPxvUesgXXMVqq*Qrq&f7I zlrlchs`m6B4u}$+yml3uKnr-BMAA4cX6Vhq=O&Boo@(iW*MVu%Q@IOsTyJb_#)^;z z1ab+__eGphp1oW1;m+aP98S}+nw~2IB=CX1hbwbdDR_ zP7u@aZfSjAyTK92HWBzZYU`GAy5+lF4}!2~I;&I8s&R2hLW??W%4Z?W-*)z!SUUXt z^%ivgxVUBbifT852XQ%Ex1 zsOvgo*XYgt{1FWUx24dliMxQ`$$&&#+x>JA(XQYZ-KzpO2EghkXa zdJr%0((q%`L+s9K8|vjLZ9rT>?IYstt=otiXCZ@IaZ1K@zEErd$1_!d=?$>2^H{Pw zCW7p927DN{sC-mx>IAK`lAZ<%OSXb#1|H(9)WZfZHNo{fj_pNKM38M}SCSZQwo+%5 zElRbUc{L&+0p(4&?y7O?1VaLZFs`$)ctsO8-|L#4ij>GmcwPc86SJAX}ed^lpr`gmj!S95a6PXQkIfizp{Yc0jU zlP1aJFMtO}KKcLr=lj3V&;R09{w^>6O@>-TSSk{K_SZowBQAHOxfXr@H;Cls*FHUc zlvhw-dBIw?U_=x<>fq!waXCcLZkSITYbe=lZy z#L3M~-g$Pd&X|oD>s`8>mlr=ZHTBUV5-w$T44mq|U)fIee?4|LAj|a8Cv`Tajp@Ug z>C*vKR41xOg-K;XVa56Zriw?%KeX#eO{DF%5GN-mg14Waj*iaoN|lZhBO!StqUBpj zGRrdR?nti<^@^>VtC{@@- zclY3>wvtqtqsI>(*GO0+D0S}s5DfQ4K7k9DiU{Asc{*L^<*wm_o|+h4p)K!LR`1Hw zQ|PIX+MKf_k9p`{_fg%HG>wdEt6k01lp1apkWsQ{?tbS3sU+Y9HYkDzLGJGrOAMC{ z_f)v=exYYSFlV6Z9Tmieg7qk`VPgrrD*srT5It*crL@*H6gvN8G-6(3OLjGK8MYM% z;z-2$DxQ@-DDpsCnoIg$e5qF%uH^r{0oA0r-oF>{Z!&l-lZ78sCYOUmC=+h^;X{b+ zl-~UVJbmUcU?zeK>oOWXLS~8-6egbp!n{K0`&StM6fw_4uVWqdb%yNy@YQy&9VVw>hDOv8 z!y7d7e^>h4Pc00WoKE$dRrnncY$32gmnC;~YXmI~sgmbi*>~nD4;n^IIjW&2pvi!m zM2n4AH&6Ga=0xJAYW}xLC}y z`Pi7VptF(Tm-JAA#-SkVPCG0Wx&b6eRwwGG=fqA57m>|NYS>PpZT3|dpf_K32zCt> z-IczQ#TWoyfpL_C?FZ34f4179;)knKUkYt*JdXTEA($*ZL zhJrj<%xXivKlgtI#V6O)9*8^z=6mIdwzTxLi2ro+v+VKSK5DiVCNVAqmmL*{5?Z~j z9;uvQl6m!tVDW93ycxcEw291HMshhbxYHb*t?QEXj*Ae>wMfOa=kt#?P|kLi7cihH z$C8penpll~)1V!+5y%Y0WL-;Z(N<=qYi1Dp%4t4{_*STAQ!odfHQFNzaZJ8u&O z&9an%Kn~00H|afS#Qk6O_M7~)yR%7%^g2H{6B)EpngQE}h99j7iEH#hJH3O}zsg>^ zZIyiU#tA`R_6KxJgb5m*TxB$4`xYZ0pd~B4mDY9cHRSUT8D*K9yl&#cru28#$f`J@ z?(@zcpE`1)x+*9lzN0xeMC>knAC()?Sn)~%FbCsL>gtX!ZEo!5BE{fBR+ZU0OHv=T zaP;Pl+L4BbmAuT}#5gYV4~3DenU9(eEJ6@e1rpRW%MoK+nxQJpM7)?R5r zcLvoU=Y{OSXKz|HG8?5^8tY?_0+?PiP%gVc3UwT^(J;YH^d0-*SK}y01N@^hu8o+x$qOz}gf}I8(7KonvKF@2Kz8 z$z>$Y8hhB#Cryr#$Bkp(NWtXBG|yTVe$Jez&Z9fIgpoDN_Y=h4FUTL))xsHKiBJx-$PXMw5pxO zU##>xhL76S93>&A!vyGSorf-?$G;{2d;$j~4o}3=Jt}iqgPeXSakSqUQ%UKc_<jnxJwxy$Etq#VMwlb zA40*G72^vAFZS*bB(t{X28;~te0viiuGnYHJvAfaGEV)}qjBlHe zKMZVcgbaqG$>m+&;w6~@-g9{@XGceRag>o&6#>vst&BaW+-?3VpIhr2`+a0BgnNv5q zc(+>s7ejX&0fTR(z2sZiD;y`;stJ0V>YiohQuLNYReaJ1X%; za0<;9c?F!nn)~~u09JEsRLPgO%fj>W+mR1C4g6O#0{8HZT{VS0%^PxfplK&>10pB8 z^raGo#T)~x4iIZkj1rE8;tS5I>F!bcV(SC5tuW}my3_4*#1!rErPNn;>30~5jV>q1 zWu*2p+TAWgY$alo^9sk0b{WSXoc>G+M#_jwu?$(mHv z?f!Ec17~cJF0n~(88HIsy~4PNFGqxU^Mo2}N+)L{Is{{Pce0uwx9n01B8~9UHk4zT zl&tVp!sNK{Z@sZoT^p|fmnJ)Ea=mJ5-+CjmIf-a|uDIDD^;bnH2o}tC8r9fi7TM{0H!R_ZRat+G>($&}tI!tf;olMZ zwpX3j;b+k4E`p}e;wqco2OFxY)@&4c%>#h#P|d%9mk?hlW~(vWcWezcDLfUzTK(>M zvIV{X=oGK>-_4TFCeRbT^WKU<${tu}OWDok?S*e}E~cRQeW{W|U>UUNq3H9Nhwh&rOLWx4tFc^@fID zY`(?{x@D<0ZrK?7(D9?4zN&BKi!_zX*8L3%&mH_bV@%T91o_Av`KBt3zGB7A$` zVkSM^PBioJ0QX0(w9nB(AN?0UPt#h?Kk&M1_!2=$n=BQI(|aywWwxML6lAyye@F-4 yZ$lUEkW}e<{hSzpalQCcsOqW diff --git a/screenshots/screenshot2.png b/screenshots/screenshot2.png index 0af97aa54a578442f19ddc24affec96168e3c154..d04e18d07545fc5b68833777035bc110c58db0dc 100644 GIT binary patch literal 60286 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

Y4a4S@@bzFvTmNZ6rw~1dC!i< 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 Z^+xnhL!vaQK#d5e*i)CMS=hT diff --git a/screenshots/screenshot3.png b/screenshots/screenshot3.png index a83c00d4599bce201252246a147ed7c5a5443eae..48bd762fb8a710e23d96c18a39344995c0fbfac0 100644 GIT binary patch literal 183010 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

0@LZu(HBGI~JHeY{HcTby=*YLT&a=uY&==% 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 TSPG910(^-J%Lr8o==uF0)HlJy From 2daba57ba85a86f449f67baec12592551a0c380d Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 20:46:25 +0000 Subject: [PATCH 021/123] Update changelog for version 31 --- CHANGELOG.md | 3 +++ README.md | 26 +++++++++++++------------- docker-compose.yml | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1a22c9..34e3014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `31` - 2023-12-03 +* Use `PROMETHEUS_ENABLED` which enables a Prometheus metrics endpoint at /metrics + ## Version `30` - 2023-06-03 * Use `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to specify path to a certificate. diff --git a/README.md b/README.md index 2b75ccb..65d9064 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:30` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:30` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:31` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:31` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -41,7 +41,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 Or run with Docker Compose @@ -58,13 +58,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:30 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:31 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:30 + image: mendhak/http-https-echo:31 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -80,7 +80,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:30 + image: mendhak/http-https-echo:31 ports: - "8080:8080" - "8443:8443" @@ -95,7 +95,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:30 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:31 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -108,7 +108,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:30 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:31 ## Do not log specific path @@ -116,13 +116,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:30 + image: mendhak/http-https-echo:31 environment: - LOG_IGNORE_PATH=/ping ports: @@ -153,7 +153,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 ``` ## Send an empty response @@ -161,7 +161,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:30 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 ``` ## Custom status code @@ -242,7 +242,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:30 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:31 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. diff --git a/docker-compose.yml b/docker-compose.yml index 09a948b..24931b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:30 + image: mendhak/http-https-echo:31 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 5f04f0ef4ae8f1e202a7f089c23562aa4e161ab5 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 3 Dec 2023 21:29:42 +0000 Subject: [PATCH 022/123] Description for multi arch image for Github Registry --- .github/workflows/publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a8112f3..b5a16ee 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -57,3 +57,4 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + output: type=image,name=target,annotation-index.org.opencontainers.image.description=Docker image that echoes request data as JSON, listens on HTTP/S, with various extra features, useful for debugging. From 68e37e30070c7862eb0cb24a0dd247ad41b538da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 11:31:36 +0000 Subject: [PATCH 023/123] Bump express from 4.18.1 to 4.19.2 Bumps [express](https://github.com/expressjs/express) from 4.18.1 to 4.19.2. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.18.1...4.19.2) --- updated-dependencies: - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 483 ++++++++++++++++++++++++++++++++++++---------- package.json | 2 +- 2 files changed, 378 insertions(+), 107 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4358815..55b441e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.17.1", + "express": "^4.19.2", + "express-prom-bundle": "^6.6.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" }, @@ -18,6 +19,15 @@ "node": ">=16.0.0" } }, + "node_modules/@opentelemetry/api": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -51,21 +61,27 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "peer": true + }, "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", + "qs": "6.11.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -93,12 +109,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -130,17 +152,17 @@ } }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -158,6 +180,22 @@ "ms": "2.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -196,6 +234,25 @@ "node": ">= 0.8" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -210,16 +267,16 @@ } }, "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -235,7 +292,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -250,6 +307,21 @@ "node": ">= 0.10.0" } }, + "node_modules/express-prom-bundle": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.6.0.tgz", + "integrity": "sha512-tZh2P2p5a8/yxQ5VbRav011Poa4R0mHqdFwn9Swe/obXDe5F0jY9wtRAfNYnqk4LXY7akyvR/nrvAHxQPWUjsQ==", + "dependencies": { + "on-finished": "^2.3.0", + "url-value-parser": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "prom-client": ">=12.0.0" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -284,32 +356,62 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "function-bind": "^1.1.1" + "es-define-property": "^1.0.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { @@ -323,6 +425,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -508,9 +621,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -547,6 +660,19 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/prom-client": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.1.tgz", + "integrity": "sha512-GVA2H96QCg2q71rjc3VYvSrVG7OpnJxyryC7dMzvfJfpJJHzQVwF3TJLfHzKORcwJpElWs1TwXLthlJAFJxq2A==", + "peer": true, + "dependencies": { + "@opentelemetry/api": "^1.4.0", + "tdigest": "^0.1.1" + }, + "engines": { + "node": "^16 || ^18 || >=20" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -560,9 +686,9 @@ } }, "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -582,9 +708,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -688,19 +814,39 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -722,6 +868,15 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "peer": true, + "dependencies": { + "bintrees": "1.0.2" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -755,6 +910,14 @@ "node": ">= 0.8" } }, + "node_modules/url-value-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.2.0.tgz", + "integrity": "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -783,6 +946,12 @@ } }, "dependencies": { + "@opentelemetry/api": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", + "peer": true + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -812,21 +981,27 @@ } } }, + "bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "peer": true + }, "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", + "qs": "6.11.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } @@ -847,12 +1022,15 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "concat-stream": { @@ -875,14 +1053,14 @@ } }, "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" }, "cookie-signature": { "version": "1.0.6", @@ -897,6 +1075,16 @@ "ms": "2.0.0" } }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -925,6 +1113,19 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -936,16 +1137,16 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -961,7 +1162,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -973,6 +1174,15 @@ "vary": "~1.1.2" } }, + "express-prom-bundle": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.6.0.tgz", + "integrity": "sha512-tZh2P2p5a8/yxQ5VbRav011Poa4R0mHqdFwn9Swe/obXDe5F0jY9wtRAfNYnqk4LXY7akyvR/nrvAHxQPWUjsQ==", + "requires": { + "on-finished": "^2.3.0", + "url-value-parser": "^2.0.0" + } + }, "finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -998,33 +1208,56 @@ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "requires": { - "function-bind": "^1.1.1" + "es-define-property": "^1.0.0" } }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1171,9 +1404,9 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" }, "on-finished": { "version": "2.4.1", @@ -1198,6 +1431,16 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "prom-client": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.1.tgz", + "integrity": "sha512-GVA2H96QCg2q71rjc3VYvSrVG7OpnJxyryC7dMzvfJfpJJHzQVwF3TJLfHzKORcwJpElWs1TwXLthlJAFJxq2A==", + "peer": true, + "requires": { + "@opentelemetry/api": "^1.4.0", + "tdigest": "^0.1.1" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1208,9 +1451,9 @@ } }, "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "requires": { "side-channel": "^1.0.4" } @@ -1221,9 +1464,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -1297,19 +1540,33 @@ "send": "0.18.0" } }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "statuses": { @@ -1325,6 +1582,15 @@ "safe-buffer": "~5.2.0" } }, + "tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "peer": true, + "requires": { + "bintrees": "1.0.2" + } + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1349,6 +1615,11 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, + "url-value-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.2.0.tgz", + "integrity": "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 19c2643..7028c20 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.17.1", + "express": "^4.19.2", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0", "express-prom-bundle": "^6.6.0" From 22ade89ebe76e4bc09393bd03cc82688131994b9 Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 28 Mar 2024 18:54:37 +0000 Subject: [PATCH 024/123] Check user at config level --- tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.sh b/tests.sh index 0dbd4f5..26cae84 100755 --- a/tests.sh +++ b/tests.sh @@ -314,7 +314,7 @@ docker stop http-echo-tests sleep 5 message " Check that container is running as user different that the user defined in image" -IMAGE_USER="$(docker image inspect mendhak/http-https-echo -f '{{ .ContainerConfig.User }}')" +IMAGE_USER="$(docker image inspect mendhak/http-https-echo -f '{{ .Config.User }}')" CONTAINER_USER="$((IMAGE_USER + 1000000))" docker run -d --name http-echo-tests --rm -u "${CONTAINER_USER}" -p 8080:8080 mendhak/http-https-echo sleep 5 From 46601deea8392e2e93cf90263669c943fb9eaac6 Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 28 Mar 2024 18:58:50 +0000 Subject: [PATCH 025/123] Version bump to 32 --- CHANGELOG.md | 3 +++ README.md | 26 +++++++++++++------------- docker-compose.yml | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34e3014..de46f6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `32` - `2024-03-28` +* Update Express to 4.19.2 to address CVE-2024-29041 + ## Version `31` - 2023-12-03 * Use `PROMETHEUS_ENABLED` which enables a Prometheus metrics endpoint at /metrics diff --git a/README.md b/README.md index 65d9064..ee052a5 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:31` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:31` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:32` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:32` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -41,7 +41,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 Or run with Docker Compose @@ -58,13 +58,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:31 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:32 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:31 + image: mendhak/http-https-echo:32 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -80,7 +80,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:31 + image: mendhak/http-https-echo:32 ports: - "8080:8080" - "8443:8443" @@ -95,7 +95,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:31 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:32 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -108,7 +108,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:31 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:32 ## Do not log specific path @@ -116,13 +116,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:31 + image: mendhak/http-https-echo:32 environment: - LOG_IGNORE_PATH=/ping ports: @@ -153,7 +153,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 ``` ## Send an empty response @@ -161,7 +161,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:31 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 ``` ## Custom status code @@ -242,7 +242,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:31 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:32 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. diff --git a/docker-compose.yml b/docker-compose.yml index 24931b7..76a6c59 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:31 + image: mendhak/http-https-echo:32 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 4732a9590a41799acfedb29cc6ad41ab48e7d7ab Mon Sep 17 00:00:00 2001 From: ash0ne Date: Sat, 30 Mar 2024 15:14:02 +0000 Subject: [PATCH 026/123] Implementing configurable CORS settings for HTTP echo server --- README.md | 11 +++++++++++ index.js | 14 ++++++++++++++ tests.sh | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/README.md b/README.md index ee052a5..6a98774 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,17 @@ docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:808 Then do a normal request via curl or browser, and you will see the `env` property in the response body. +## Setting CORS(Cross-Origin Resource Sharing) headers in the response + +Enable CORS headers in response by setting the environment variable `CORS_ALLOW_ORIGIN` to the list of allowed origins. +CORS configuration can be further fine-tuned by using the following environment variables: + +- **`CORS_ALLOW_METHODS`**: List of Http methods allowed. +- **`CORS_ALLOW_HEADERS`**: List of headers allowed. +- **`CORS_ALLOW_CREDENTIALS`**: Comma-separated list of origin URLs from which the policy allows credentials to be sent. + +None of these can be set without setting the `CORS_ALLOW_ORIGIN` variable first. By default, they will all be missing when only the `CORS_ALLOW_ORIGIN` is set and need to be explicitly set. + ## Client certificate details (mTLS) in the response diff --git a/index.js b/index.js index 03391c1..4cf2f62 100644 --- a/index.js +++ b/index.js @@ -114,6 +114,20 @@ app.all('*', (req, res) => { res.contentType(setResponseContentType); } + //Set the CORS policy + if (process.env.CORS_ALLOW_ORIGIN){ + res.header('Access-Control-Allow-Origin', process.env.CORS_ALLOW_ORIGIN); + if (process.env.CORS_ALLOW_METHODS) { + res.header('Access-Control-Allow-Methods', process.env.CORS_ALLOW_METHODS); + } + if (process.env.CORS_ALLOW_HEADERS) { + res.header('Access-Control-Allow-Headers', process.env.CORS_ALLOW_HEADERS); + } + if (process.env.CORS_ALLOW_CREDENTIALS) { + res.header('Access-Control-Allow-Credentials', process.env.CORS_ALLOW_CREDENTIALS); + } + } + //Ability to send an empty response back if (process.env.ECHO_BACK_TO_CLIENT != undefined && process.env.ECHO_BACK_TO_CLIENT == "false"){ res.end(); diff --git a/tests.sh b/tests.sh index 26cae84..d787657 100755 --- a/tests.sh +++ b/tests.sh @@ -271,6 +271,26 @@ else exit 1 fi +message " Stop containers " +docker stop http-echo-tests +sleep 5 + +message " Start container with CORS_CONFIG" +docker run -d --rm \ + -e CORS_ALLOW_ORIGIN="http://example.com" -e CORS_ALLOW_HEADERS="x-custom-test-header" \ + --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +sleep 5 +# Check if the expected CORS headers are present in the response +if curl -s -i http://localhost:8080/ 2>&1 | grep -q -E \ + "Access-Control-Allow-Headers: x-custom-test-header" && + curl -s -i http://localhost:8080/ 2>&1 | grep -q -E \ + "Access-Control-Allow-Origin: http://example.com"; then + passed "CORS_CONFIG expected CORS headers found in response" +else + failed "CORS_CONFIG failed." + docker logs http-echo-tests + exit 1 +fi message " Stop containers " docker stop http-echo-tests From f6ee1e5a9a5647411c71283490741445732e7efa Mon Sep 17 00:00:00 2001 From: ash0ne Date: Sat, 30 Mar 2024 15:18:37 +0000 Subject: [PATCH 027/123] Updating the index in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a98774..94145d8 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ This image is executed as non root by default and is fully compliant with Kubern - [Add a delay before response](#add-a-delay-before-response) - [Only return body in the response](#only-return-body-in-the-response) - [Include environment variables in the response](#include-environment-variables-in-the-response) +- [Configuring CORS policy](#setting-corscross-origin-resource-sharing-headers-in-the-response) - [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) - [Prometheus Metrics](#prometheus-metrics) - [Screenshots](#screenshots) From 6e7f7f3beebd8eeb6f61c55bca82b280e9508b63 Mon Sep 17 00:00:00 2001 From: ash0ne Date: Sat, 30 Mar 2024 15:26:39 +0000 Subject: [PATCH 028/123] Updating README for CORS settings --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94145d8..1d2f628 100644 --- a/README.md +++ b/README.md @@ -257,7 +257,7 @@ CORS configuration can be further fine-tuned by using the following environment - **`CORS_ALLOW_HEADERS`**: List of headers allowed. - **`CORS_ALLOW_CREDENTIALS`**: Comma-separated list of origin URLs from which the policy allows credentials to be sent. -None of these can be set without setting the `CORS_ALLOW_ORIGIN` variable first. By default, they will all be missing when only the `CORS_ALLOW_ORIGIN` is set and need to be explicitly set. +None of these CORS settings can be set without setting the `CORS_ALLOW_ORIGIN` first. By default, they will all be missing when only the `CORS_ALLOW_ORIGIN` is set and need to be explicitly specified alongside `CORS_ALLOW_ORIGIN`. ## Client certificate details (mTLS) in the response From bc4de52437f74bf380729742682ce8ad9707423e Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 13:55:43 +0100 Subject: [PATCH 029/123] Try the new gha cache in docker build action --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1922fb9..ffe172a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,6 +51,8 @@ jobs: context: . platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le push: false + cache-from: type=gha + cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 187b432f0122b143d656eebdb97a22d8df11892b Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:01:33 +0100 Subject: [PATCH 030/123] Update actions to their latest versions --- .github/workflows/build.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffe172a..2078bcc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,13 +22,13 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Inspect builder run: | @@ -40,13 +40,13 @@ jobs: - name: Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | mendhak/http-https-echo - name: Build the image multi-platform - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le @@ -64,8 +64,7 @@ jobs: uses: anchore/scan-action@v3 with: image: "mendhak/http-https-echo:latest" - debug: false - acs-report-enable: true + output-format: sarif severity-cutoff: critical - name: upload Anchore scan SARIF report From 1bb4d72ca4efd43cf059f802103583d26d70f826 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:08:45 +0100 Subject: [PATCH 031/123] Update actions to their latest versions --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2078bcc..ed97ee7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,6 +68,6 @@ jobs: severity-cutoff: critical - name: upload Anchore scan SARIF report - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: ${{ steps.scan.outputs.sarif }} From 44ab72afbf76992be8cd88654ea93f104a3fcd34 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:11:33 +0100 Subject: [PATCH 032/123] Check if we're in GHA --- tests.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests.sh b/tests.sh index d787657..3ed2626 100755 --- a/tests.sh +++ b/tests.sh @@ -26,6 +26,14 @@ if ! [ -x "$(command -v jq)" ]; then sudo apt -y install jq fi +message " Check if we're in Github Actions " +if [ -n "${GITHUB_ACTIONS}" ]; then + message " Running in Github Actions " +fi + +message "List the docker images" +docker images + message " Build image " docker build -t mendhak/http-https-echo:latest . From 90098666d818f37e70ac55f585173d514c93533a Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:14:30 +0100 Subject: [PATCH 033/123] Get build action to load into local docker images --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed97ee7..b64d4b6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,6 +51,7 @@ jobs: context: . platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le push: false + load: true cache-from: type=gha cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} From 1a80aecf0e26d7c32743ef0912b967f06431cbb7 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:33:11 +0100 Subject: [PATCH 034/123] If we're in GHA, expect the image to be loaded locally --- .github/workflows/build.yml | 12 ++++++++++++ tests.sh | 14 ++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b64d4b6..90c2f6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,6 +57,18 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + # Due to bug https://github.com/docker/buildx/issues/59, need to build for single platform, load, then run tests. + - name: Build the image single platform and load it + uses: docker/build-push-action@v5 + with: + context: . + push: false + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: "latest" + labels: ${{ steps.meta.outputs.labels }} + - name: Build the image single platform and run tests run: ./tests.sh diff --git a/tests.sh b/tests.sh index 3ed2626..1a6f06a 100755 --- a/tests.sh +++ b/tests.sh @@ -28,14 +28,16 @@ fi message " Check if we're in Github Actions " if [ -n "${GITHUB_ACTIONS}" ]; then - message " Running in Github Actions " + docker images + if [ -z "$(docker images -q mendhak/http-https-echo:latest 2> /dev/null)" ]; then + echo "Docker image mendhak/http-https-echo:latest not found. Exiting." + exit 1 + fi +else + message " Local run. Build image " + docker build -t mendhak/http-https-echo:latest . fi -message "List the docker images" -docker images - -message " Build image " -docker build -t mendhak/http-https-echo:latest . mkdir -p testarea pushd testarea From 11370007deba25a6438acc922c40461bdf04ec43 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:35:08 +0100 Subject: [PATCH 035/123] If we're in GHA, expect the image to be loaded locally --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90c2f6b..e9c1828 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,7 +51,6 @@ jobs: context: . platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le push: false - load: true cache-from: type=gha cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} From b13b09120f5c65ad6d30a8e822863f527882bf51 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:36:52 +0100 Subject: [PATCH 036/123] If we're in GHA, expect the image to be loaded locally --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e9c1828..531efca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: load: true cache-from: type=gha cache-to: type=gha,mode=max - tags: "latest" + tags: "mendhak/http-https-echo:latest" labels: ${{ steps.meta.outputs.labels }} - name: Build the image single platform and run tests From 0f453074efc6e24f5d87cf1998cc3f64c0563e57 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 14:52:10 +0100 Subject: [PATCH 037/123] Rename the image tag to use :testing so it's distinct from any other built image --- .github/workflows/build.yml | 2 +- tests.sh | 44 ++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 531efca..c755b75 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: load: true cache-from: type=gha cache-to: type=gha,mode=max - tags: "mendhak/http-https-echo:latest" + tags: "mendhak/http-https-echo:testing" labels: ${{ steps.meta.outputs.labels }} - name: Build the image single platform and run tests diff --git a/tests.sh b/tests.sh index 1a6f06a..d311be7 100755 --- a/tests.sh +++ b/tests.sh @@ -27,15 +27,15 @@ if ! [ -x "$(command -v jq)" ]; then fi message " Check if we're in Github Actions " -if [ -n "${GITHUB_ACTIONS}" ]; then +if [ -n "${GITHUB_ACTIONS:-}" ]; then docker images - if [ -z "$(docker images -q mendhak/http-https-echo:latest 2> /dev/null)" ]; then - echo "Docker image mendhak/http-https-echo:latest not found. Exiting." + if [ -z "$(docker images -q mendhak/http-https-echo:testing 2> /dev/null)" ]; then + echo "Docker image mendhak/http-https-echo:testing not found. Exiting." exit 1 fi else message " Local run. Build image " - docker build -t mendhak/http-https-echo:latest . + docker build -t mendhak/http-https-echo:testing . fi @@ -46,7 +46,7 @@ message " Cleaning up from previous test run " docker ps -aq --filter "name=http-echo-tests" | grep -q . && docker stop http-echo-tests && docker rm -f http-echo-tests message " Start container normally " -docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 @@ -159,7 +159,7 @@ docker stop http-echo-tests sleep 5 message " Start container with different internal ports " -docker run -d --rm -e HTTP_PORT=8888 -e HTTPS_PORT=9999 --name http-echo-tests -p 8080:8888 -p 8443:9999 -t mendhak/http-https-echo +docker run -d --rm -e HTTP_PORT=8888 -e HTTPS_PORT=9999 --name http-echo-tests -p 8080:8888 -p 8443:9999 -t mendhak/http-https-echo:testing sleep 5 message " Make http(s) request, and test the path, method and header. " @@ -193,7 +193,7 @@ docker stop http-echo-tests sleep 5 message " Start container with empty responses " -docker run -d --rm -e ECHO_BACK_TO_CLIENT=false --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e ECHO_BACK_TO_CLIENT=false --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 REQUEST=$(curl -s -k http://localhost:8080/a/b/c) if [[ -z ${REQUEST} ]] @@ -210,7 +210,7 @@ docker stop http-echo-tests sleep 5 message " Start container with response body only " -docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 RESPONSE=$(curl -s -k -X POST -d 'cauliflower' http://localhost:8080/a/b/c?response_body_only=true) if [[ ${RESPONSE} == "cauliflower" ]] @@ -228,7 +228,7 @@ docker stop http-echo-tests sleep 5 message " Start container with JWT_HEADER " -docker run -d --rm -e JWT_HEADER=Authentication --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e JWT_HEADER=Authentication --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 REQUEST=$(curl -s -k -H "Authentication: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" https://localhost:8443/ ) @@ -249,7 +249,7 @@ sleep 5 message " Start container with LOG_IGNORE_PATH " -docker run -d --rm -e LOG_IGNORE_PATH=/ping --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e LOG_IGNORE_PATH=/ping --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 curl -s -k -X POST -d "banana" https://localhost:8443/ping > /dev/null @@ -269,7 +269,7 @@ docker stop http-echo-tests sleep 5 message " Start container with DISABLE_REQUEST_LOGS " -docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 curl -s -k -X GET https://localhost:8443/strawberry > /dev/null if [ $(docker logs http-echo-tests | grep -c "GET /strawberry HTTP/1.1") -eq 0 ] @@ -288,7 +288,7 @@ sleep 5 message " Start container with CORS_CONFIG" docker run -d --rm \ -e CORS_ALLOW_ORIGIN="http://example.com" -e CORS_ALLOW_HEADERS="x-custom-test-header" \ - --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo + --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 # Check if the expected CORS headers are present in the response if curl -s -i http://localhost:8080/ 2>&1 | grep -q -E \ @@ -307,7 +307,7 @@ docker stop http-echo-tests sleep 5 message " Start container with LOG_WITHOUT_NEWLINE " -docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null @@ -327,7 +327,7 @@ docker stop http-echo-tests sleep 5 message " Check that container is running as a NON ROOT USER by default" -docker run -d --name http-echo-tests --rm mendhak/http-https-echo +docker run -d --name http-echo-tests --rm mendhak/http-https-echo:testing WHOAMI=$(docker exec http-echo-tests whoami) @@ -344,9 +344,9 @@ docker stop http-echo-tests sleep 5 message " Check that container is running as user different that the user defined in image" -IMAGE_USER="$(docker image inspect mendhak/http-https-echo -f '{{ .Config.User }}')" +IMAGE_USER="$(docker image inspect mendhak/http-https-echo:testing -f '{{ .Config.User }}')" CONTAINER_USER="$((IMAGE_USER + 1000000))" -docker run -d --name http-echo-tests --rm -u "${CONTAINER_USER}" -p 8080:8080 mendhak/http-https-echo +docker run -d --name http-echo-tests --rm -u "${CONTAINER_USER}" -p 8080:8080 mendhak/http-https-echo:testing sleep 5 curl -s http://localhost:8080 > /dev/null @@ -369,7 +369,7 @@ message " Check that mTLS server responds with client certificate details" openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout privkey.pem -out fullchain.pem \ -subj "/CN=client.example.net" \ -addext "subjectAltName=DNS:client.example.net" -docker run -d --rm -e MTLS_ENABLE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e MTLS_ENABLE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 COMMON_NAME="$(curl -sk --cert fullchain.pem --key privkey.pem https://localhost:8443/ | jq -r '.clientCertificate.subject.CN')" SAN="$(curl -sk --cert fullchain.pem --key privkey.pem https://localhost:8443/ | jq -r '.clientCertificate.subjectaltname')" @@ -422,7 +422,7 @@ docker run -d --rm \ -e HTTPS_CERT_FILE="${container_https_cert_file}" \ -v "${https_key_file}:${container_https_key_file}:ro,z" \ -e HTTPS_KEY_FILE="${container_https_key_file}" \ - --name http-echo-tests -p 8443:8443 -t mendhak/http-https-echo + --name http-echo-tests -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 REQUEST_WITH_STATUS_CODE="$(curl -s --cacert "$(pwd)/server_fullchain.pem" -o /dev/null -w "%{http_code}" \ @@ -440,7 +440,7 @@ docker stop http-echo-tests sleep 5 message " Check that environment variables returned in response if enabled" -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 RESPONSE_BODY="$(curl -sk https://localhost:8443/ | jq -r '.env.ECHO_INCLUDE_ENV_VARS')" @@ -457,7 +457,7 @@ docker stop http-echo-tests sleep 5 message " Check that environment variables are not present in response by default" -docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 RESPONSE_BODY_ENV_CHECK="$(curl -sk https://localhost:8443/ | jq 'has("env")')" @@ -474,7 +474,7 @@ docker stop http-echo-tests sleep 5 message " Start container with PROMETHEUS disabled " -docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null @@ -495,7 +495,7 @@ docker stop http-echo-tests sleep 5 message " Start container with PROMETHEUS enabled " -docker run -d -e PROMETHEUS_ENABLED=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo +docker run -d -e PROMETHEUS_ENABLED=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null From 938cb32532f796795a946db6c08b10129c4aa0d3 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 15:24:52 +0100 Subject: [PATCH 038/123] GHA vs local --- tests.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests.sh b/tests.sh index d311be7..6405d80 100755 --- a/tests.sh +++ b/tests.sh @@ -26,15 +26,16 @@ if ! [ -x "$(command -v jq)" ]; then sudo apt -y install jq fi -message " Check if we're in Github Actions " +message " Check if we're in Github Actions or local run " if [ -n "${GITHUB_ACTIONS:-}" ]; then + echo " Github Actions. Image should already be built." docker images if [ -z "$(docker images -q mendhak/http-https-echo:testing 2> /dev/null)" ]; then echo "Docker image mendhak/http-https-echo:testing not found. Exiting." exit 1 fi else - message " Local run. Build image " + echo " Local run. Build image " docker build -t mendhak/http-https-echo:testing . fi From e76db1ce3bda7a415fc95a26ecb57de48a42b56b Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 15:40:55 +0100 Subject: [PATCH 039/123] Use latest actions in publish workflow --- .github/workflows/publish.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b5a16ee..3cf30d4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,14 +11,14 @@ jobs: publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Inspect builder run: | @@ -29,13 +29,13 @@ jobs: echo "Platforms: ${{ steps.buildx.outputs.platforms }}" - name: Log in to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: Log in to GitHub Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -43,18 +43,19 @@ jobs: - name: Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | mendhak/http-https-echo ghcr.io/mendhak/http-https-echo - name: Build and push image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - output: type=image,name=target,annotation-index.org.opencontainers.image.description=Docker image that echoes request data as JSON, listens on HTTP/S, with various extra features, useful for debugging. + cache-from: type=gha + cache-to: type=gha,mode=max From 959486c339e1625528486a3b3d9ec357e389d7bf Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 15:43:05 +0100 Subject: [PATCH 040/123] Build test image and use in test step --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c755b75..9721bf1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,7 +57,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} # Due to bug https://github.com/docker/buildx/issues/59, need to build for single platform, load, then run tests. - - name: Build the image single platform and load it + - name: Build a test image single platform and load it uses: docker/build-push-action@v5 with: context: . @@ -68,7 +68,7 @@ jobs: tags: "mendhak/http-https-echo:testing" labels: ${{ steps.meta.outputs.labels }} - - name: Build the image single platform and run tests + - name: Run tests using the test image run: ./tests.sh - name: Scan the image From 8bcc0832639d28af69bd3f334ef80bb386efd57b Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 15:52:53 +0100 Subject: [PATCH 041/123] Try to split into multiple jobs --- .github/workflows/build.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9721bf1..7c26046 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,12 +14,11 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - # This workflow contains a single job called "build" + build: - # The type of runner that the job will run on + runs-on: ubuntu-latest - # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 @@ -55,7 +54,10 @@ jobs: cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - + test: + runs-on: ubuntu-latest + needs: build + steps: # Due to bug https://github.com/docker/buildx/issues/59, need to build for single platform, load, then run tests. - name: Build a test image single platform and load it uses: docker/build-push-action@v5 @@ -66,11 +68,13 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max tags: "mendhak/http-https-echo:testing" - labels: ${{ steps.meta.outputs.labels }} - name: Run tests using the test image run: ./tests.sh - + scan: + runs-on: ubuntu-latest + needs: build + steps: - name: Scan the image id: scan uses: anchore/scan-action@v3 From 98969a72fbeafdf702196ce74505b39bef77c706 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 15:55:46 +0100 Subject: [PATCH 042/123] Revert "Try to split into multiple jobs" This reverts commit 8bcc0832639d28af69bd3f334ef80bb386efd57b. --- .github/workflows/build.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c26046..9721bf1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,11 +14,12 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - + # This workflow contains a single job called "build" build: - + # The type of runner that the job will run on runs-on: ubuntu-latest + # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 @@ -54,10 +55,7 @@ jobs: cache-to: type=gha,mode=max tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - test: - runs-on: ubuntu-latest - needs: build - steps: + # Due to bug https://github.com/docker/buildx/issues/59, need to build for single platform, load, then run tests. - name: Build a test image single platform and load it uses: docker/build-push-action@v5 @@ -68,13 +66,11 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max tags: "mendhak/http-https-echo:testing" + labels: ${{ steps.meta.outputs.labels }} - name: Run tests using the test image run: ./tests.sh - scan: - runs-on: ubuntu-latest - needs: build - steps: + - name: Scan the image id: scan uses: anchore/scan-action@v3 From cd8125c3ed5f231c2d559d6fc391772e99b249b2 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 7 Apr 2024 16:27:41 +0100 Subject: [PATCH 043/123] Version bump to 33 and changelog --- CHANGELOG.md | 3 +++ README.md | 26 +++++++++++++------------- docker-compose.yml | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de46f6c..17c65fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `33` - `2024-04-07` +* Implementing configurable CORS settings by [ash0ne](https://github.com/mendhak/docker-http-https-echo/pull/65). + ## Version `32` - `2024-03-28` * Update Express to 4.19.2 to address CVE-2024-29041 diff --git a/README.md b/README.md index 1d2f628..1ed97e0 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:32` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:32` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:33` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:33` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -42,7 +42,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 Or run with Docker Compose @@ -59,13 +59,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:32 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:33 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:32 + image: mendhak/http-https-echo:33 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -81,7 +81,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:32 + image: mendhak/http-https-echo:33 ports: - "8080:8080" - "8443:8443" @@ -96,7 +96,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:32 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:33 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -109,7 +109,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:32 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:33 ## Do not log specific path @@ -117,13 +117,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:32 + image: mendhak/http-https-echo:33 environment: - LOG_IGNORE_PATH=/ping ports: @@ -154,7 +154,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 ``` ## Send an empty response @@ -162,7 +162,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:32 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 ``` ## Custom status code @@ -243,7 +243,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:32 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:33 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. diff --git a/docker-compose.yml b/docker-compose.yml index 76a6c59..515f474 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:32 + image: mendhak/http-https-echo:33 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From ee009519ceb2884a4f5f2ea5c5d0ab31a743e487 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 10:06:37 +0100 Subject: [PATCH 044/123] Option to try to preserve the case of the headers. Issue #67 --- index.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/index.js b/index.js index 4cf2f62..7986e20 100644 --- a/index.js +++ b/index.js @@ -69,6 +69,22 @@ app.all('*', (req, res) => { } }; + if(process.env.PRESERVE_HEADER_CASE){ + let newHeaders = {...req.headers}; + + // req.headers is in lowercase, processed, deduplicated. req.rawHeaders is not. + // Match on the preserved case of the header name, populate newHeaders with preserved case and processed value. + for (let i = 0; i < req.rawHeaders.length; i += 2) { + let preservedHeaderName = req.rawHeaders[i]; + if (preservedHeaderName == preservedHeaderName.toLowerCase()) { continue; } + + newHeaders[preservedHeaderName] = req.header(preservedHeaderName); + delete newHeaders[preservedHeaderName.toLowerCase()]; + } + echo.headers = newHeaders; + } + + //Add client certificate details to the output, if present //This only works if `requestCert` is true when starting the server. if(req.socket.getPeerCertificate){ From 84ef8bff25bb155e92241e98ac1113923c444953 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 10:22:03 +0100 Subject: [PATCH 045/123] Output scan results as a table --- .github/workflows/build.yml | 2 +- tests.sh | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9721bf1..75f69b5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,7 +76,7 @@ jobs: uses: anchore/scan-action@v3 with: image: "mendhak/http-https-echo:latest" - output-format: sarif + output-format: table severity-cutoff: critical - name: upload Anchore scan SARIF report diff --git a/tests.sh b/tests.sh index 6405d80..68f44a3 100755 --- a/tests.sh +++ b/tests.sh @@ -510,6 +510,24 @@ else exit 1 fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + +message " Start container with PRESERVE_HEADER_CASE enabled " +docker run -d -e PRESERVE_HEADER_CASE=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing + +sleep 5 +HEADER_CASE_CHECK=$(curl -s -H "prEseRVe-CaSE: A1b2C3" -H 'x-a-b: 999' -H 'X-a-B: 13' localhost:8080 | jq -r '.headers."prEseRVe-CaSE"') +if [[ "$HEADER_CASE_CHECK" == "A1b2C3" ]] +then + passed "PRESERVE_HEADER_CASE enabled" +else + failed "PRESERVE_HEADER_CASE failed" + exit 1 +fi + message " Stop containers " docker stop http-echo-tests sleep 5 From 30085cea03d796ab26ed15802d5b81f6bfbd2969 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 10:33:55 +0100 Subject: [PATCH 046/123] Node 20 update --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ff95473..1441da3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine AS build +FROM node:20-alpine AS build WORKDIR /app COPY . /app From 13618a9cd8a3664cbe4237183553e8a00dc07ec4 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 11:19:07 +0100 Subject: [PATCH 047/123] Try combining multiple tags in one build --- .github/workflows/build.yml | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 75f69b5..566b4c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,16 +45,17 @@ jobs: images: | mendhak/http-https-echo - - name: Build the image multi-platform - uses: docker/build-push-action@v5 - with: - context: . - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le - push: false - cache-from: type=gha - cache-to: type=gha,mode=max - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + # Commenting out, possible bug: https://github.com/nodejs/docker-node/issues/1946 + # - name: Build the image multi-platform + # uses: docker/build-push-action@v5 + # with: + # context: . + # platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le + # push: false + # cache-from: type=gha + # cache-to: type=gha,mode=max + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} # Due to bug https://github.com/docker/buildx/issues/59, need to build for single platform, load, then run tests. - name: Build a test image single platform and load it @@ -65,7 +66,9 @@ jobs: load: true cache-from: type=gha cache-to: type=gha,mode=max - tags: "mendhak/http-https-echo:testing" + tags: | + ${{ steps.meta.outputs.tags }} + "mendhak/http-https-echo:testing" labels: ${{ steps.meta.outputs.labels }} - name: Run tests using the test image From 8c5338242a258b4d0fdcc64fb308de4ef39d26f9 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 11:28:10 +0100 Subject: [PATCH 048/123] Update apk packages --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 1441da3..422324a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ RUN set -ex \ # Build JS-Application && npm install --production \ # Generate SSL-certificate (for HTTPS) + && apk update && apk upgrade \ && apk --no-cache add openssl \ && openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout privkey.pem -out fullchain.pem \ -subj "/C=GB/ST=London/L=London/O=Mendhak/CN=my.example.com" \ From 67b44714e15649ea0b0b30fdf70f7b9ff5c08566 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 11:43:45 +0100 Subject: [PATCH 049/123] Try node 22 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 422324a..b7b1d63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine AS build +FROM node:22-alpine AS build WORKDIR /app COPY . /app From 4fdde33feb3e19c653b2e4c8bc4efbe56fafe56d Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 12:04:07 +0100 Subject: [PATCH 050/123] apk upgrade was not necessary here --- Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b7b1d63..6e7cc65 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,6 @@ RUN set -ex \ # Build JS-Application && npm install --production \ # Generate SSL-certificate (for HTTPS) - && apk update && apk upgrade \ && apk --no-cache add openssl \ && openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout privkey.pem -out fullchain.pem \ -subj "/C=GB/ST=London/L=London/O=Mendhak/CN=my.example.com" \ @@ -20,7 +19,7 @@ RUN set -ex \ && chown -R node:node /app \ && chmod +r /app/privkey.pem -FROM node:16-alpine AS final +FROM node:22-alpine AS final LABEL \ org.opencontainers.image.title="http-https-echo" \ org.opencontainers.image.description="Docker image that echoes request data as JSON; listens on HTTP/S, with various extra features, useful for debugging." \ From cdf54cfac0e33f3080f4c6b1bea0d165c24b1195 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 12:52:21 +0100 Subject: [PATCH 051/123] Grype passes locally but not on GH actions --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 566b4c3..a89eebf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,9 +78,10 @@ jobs: id: scan uses: anchore/scan-action@v3 with: - image: "mendhak/http-https-echo:latest" - output-format: table - severity-cutoff: critical + image: "mendhak/http-https-echo:testing" + output-format: sarif + # severity-cutoff: critical + fail-build: false - name: upload Anchore scan SARIF report uses: github/codeql-action/upload-sarif@v3 From 24c9a3925f75e2c25ed663013acce8e99c290527 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 13:48:34 +0100 Subject: [PATCH 052/123] Try node 20 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6e7cc65..643a344 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22-alpine AS build +FROM node:20-alpine AS build WORKDIR /app COPY . /app @@ -19,7 +19,7 @@ RUN set -ex \ && chown -R node:node /app \ && chmod +r /app/privkey.pem -FROM node:22-alpine AS final +FROM node:20-alpine AS final LABEL \ org.opencontainers.image.title="http-https-echo" \ org.opencontainers.image.description="Docker image that echoes request data as JSON; listens on HTTP/S, with various extra features, useful for debugging." \ From 07869f5d7d70cbca0f813fe5c8d8a5f11f47102e Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 14:14:00 +0100 Subject: [PATCH 053/123] Try node 18 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 643a344..ed7a692 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine AS build +FROM node:18-alpine AS build WORKDIR /app COPY . /app @@ -19,7 +19,7 @@ RUN set -ex \ && chown -R node:node /app \ && chmod +r /app/privkey.pem -FROM node:20-alpine AS final +FROM node:18-alpine AS final LABEL \ org.opencontainers.image.title="http-https-echo" \ org.opencontainers.image.description="Docker image that echoes request data as JSON; listens on HTTP/S, with various extra features, useful for debugging." \ From d68877fee1310b52d1f98457b921d845d19e53a3 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 14:36:12 +0100 Subject: [PATCH 054/123] Changelog update --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17c65fe..7fbb12d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ + +## Version `34` - `2024-08-11` +* Set `PRESERVE_HEADER_CASE` to `1` to attempt to preserve the case of headers in the response. + ## Version `33` - `2024-04-07` * Implementing configurable CORS settings by [ash0ne](https://github.com/mendhak/docker-http-https-echo/pull/65). From be4acc6d852bd7a4a89ef5e607dc93b526f20464 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 15:47:30 +0100 Subject: [PATCH 055/123] Instructions for header case --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 1ed97e0..7dbd912 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ This image is executed as non root by default and is fully compliant with Kubern - [Include environment variables in the response](#include-environment-variables-in-the-response) - [Configuring CORS policy](#setting-corscross-origin-resource-sharing-headers-in-the-response) - [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) +- [Preserve the case of headers in response body](#preserve-the-case-of-headers-in-response-body) - [Prometheus Metrics](#prometheus-metrics) - [Screenshots](#screenshots) - [Building](#building) @@ -278,6 +279,14 @@ If you browse to https://localhost:8443/ in Firefox, you won't get prompted to s openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx ``` +## Preserve the case of headers in response body + +By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. + +```bash +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 +``` + ## Prometheus Metrics To expose http performance metrics, set the `PROMETHEUS_ENABLED` environment variable to true, the metrics will be available at `/metrics`. This uses the [`express-prom-bundle`](https://github.com/jochen-schweizer/express-prom-bundle) middleware From f538f527696bc1cc99107b76d40e628efd5ff124 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 16:42:47 +0100 Subject: [PATCH 056/123] Set a file's contents which will override the response output Issue #68 --- index.js | 7 +++++++ tests.sh | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/index.js b/index.js index 7986e20..e22e3fa 100644 --- a/index.js +++ b/index.js @@ -47,6 +47,13 @@ app.use(function(req, res, next){ //Handle all paths app.all('*', (req, res) => { + + if(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH){ + // Path is relative to current directory + res.sendFile(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH, { root : __dirname}); + return; + } + const echo = { path: req.path, headers: req.headers, diff --git a/tests.sh b/tests.sh index 68f44a3..c974535 100755 --- a/tests.sh +++ b/tests.sh @@ -532,6 +532,23 @@ message " Stop containers " docker stop http-echo-tests sleep 5 +message " Start container with a custom response body from a file " +echo "

Hello World

" > test.html +docker run -d --rm -v ${PWD}/test.html:/app/test.html --name http-echo-tests -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:testing +sleep 5 +RESPONSE_BODY=$(curl -s http://localhost:8080) +if [[ "$RESPONSE_BODY" == "

Hello World

" ]] +then + passed "Custom response body from file" +else + failed "Custom response body from file failed" + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + popd rm -rf testarea message "DONE" From fbb3bfae8c53a9592bfc3dd263b3789d1e2ce9e0 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 16:44:46 +0100 Subject: [PATCH 057/123] Set a file's contents which will override the response output --- tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.sh b/tests.sh index c974535..12cd8a4 100755 --- a/tests.sh +++ b/tests.sh @@ -48,7 +48,7 @@ docker ps -aq --filter "name=http-echo-tests" | grep -q . && docker stop http-ec message " Start container normally " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +sleep 10 message " Make http(s) request, and test the path, method, header and status code. " From bb848e8f2da2f9e1d0839a615597add36f54add9 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 11 Aug 2024 17:07:19 +0100 Subject: [PATCH 058/123] Instructions for overriding body with file content --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 7dbd912..dfa9a40 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ This image is executed as non root by default and is fully compliant with Kubern - [Configuring CORS policy](#setting-corscross-origin-resource-sharing-headers-in-the-response) - [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) - [Preserve the case of headers in response body](#preserve-the-case-of-headers-in-response-body) +- [Override the response body with a file](#override-the-response-body-with-a-file) - [Prometheus Metrics](#prometheus-metrics) - [Screenshots](#screenshots) - [Building](#building) @@ -287,6 +288,16 @@ By default, the headers in the response body are lowercased. To attempt to prese docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 ``` +## Override the response body with a file + +To override the response body with a file, set the environment variable `OVERRIDE_RESPONSE_BODY_FILE_PATH` to a file path. +The file path needs to be in the `/app` directory. + +```bash +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:33 +``` + + ## Prometheus Metrics To expose http performance metrics, set the `PROMETHEUS_ENABLED` environment variable to true, the metrics will be available at `/metrics`. This uses the [`express-prom-bundle`](https://github.com/jochen-schweizer/express-prom-bundle) middleware From 1e5dfe26c6669e7fcc9dc596933f826a5917c23f Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 17 Aug 2024 11:05:02 +0100 Subject: [PATCH 059/123] Changelog and update to version 34 --- CHANGELOG.md | 3 ++- README.md | 30 +++++++++++++++--------------- docker-compose.yml | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fbb12d..900adfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -## Version `34` - `2024-08-11` +## Version `34` - `2024-08-17` * Set `PRESERVE_HEADER_CASE` to `1` to attempt to preserve the case of headers in the response. +* Set `OVERRIDE_RESPONSE_BODY_FILE_PATH` to a path, to override the response body with the contents of that file. ## Version `33` - `2024-04-07` * Implementing configurable CORS settings by [ash0ne](https://github.com/mendhak/docker-http-https-echo/pull/65). diff --git a/README.md b/README.md index dfa9a40..5b2097d 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:33` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:33` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:34` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:34` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:33 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:34 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:33 + image: mendhak/http-https-echo:34 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:33 + image: mendhak/http-https-echo:34 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:33 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:34 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:33 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:34 ## Do not log specific path @@ -119,13 +119,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:33 + image: mendhak/http-https-echo:34 environment: - LOG_IGNORE_PATH=/ping ports: @@ -156,7 +156,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 ``` ## Send an empty response @@ -164,7 +164,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 ``` ## Custom status code @@ -245,7 +245,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:33 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:34 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -285,7 +285,7 @@ openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 ``` ## Override the response body with a file @@ -294,7 +294,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:33 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:34 ``` diff --git a/docker-compose.yml b/docker-compose.yml index 515f474..8ffda98 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:33 + image: mendhak/http-https-echo:34 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 5b4ef46392222f3bef688b84c710e04bbcd95a64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 06:32:45 +0000 Subject: [PATCH 060/123] Bump path-to-regexp and express Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.10 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together. Updates `path-to-regexp` from 0.1.7 to 0.1.10 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.10) Updates `express` from 4.19.2 to 4.20.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 214 ++++++++++++++++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 158 insertions(+), 58 deletions(-) diff --git a/package-lock.json b/package-lock.json index 55b441e..0fc6578 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.19.2", + "express": "^4.20.0", "express-prom-bundle": "^6.6.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" @@ -68,9 +68,9 @@ "peer": true }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -80,7 +80,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -90,6 +90,20 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "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", @@ -267,36 +281,36 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", + "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -322,6 +336,14 @@ "prom-client": ">=12.0.0" } }, + "node_modules/express/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -539,9 +561,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", @@ -621,9 +646,12 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -656,9 +684,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "node_modules/prom-client": { "version": "15.1.1", @@ -773,9 +801,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -801,9 +829,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -814,6 +842,34 @@ "node": ">= 0.8.0" } }, + "node_modules/serve-static/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static/node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -988,9 +1044,9 @@ "peer": true }, "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -1000,10 +1056,20 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" + }, + "dependencies": { + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "requires": { + "side-channel": "^1.0.6" + } + } } }, "buffer-equal-constant-time": { @@ -1137,41 +1203,48 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", + "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + } } }, "express-prom-bundle": { @@ -1344,9 +1417,9 @@ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" }, "methods": { "version": "1.1.2", @@ -1404,9 +1477,9 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, "on-finished": { "version": "2.4.1", @@ -1427,9 +1500,9 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "prom-client": { "version": "15.1.1", @@ -1503,9 +1576,9 @@ } }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "requires": { "debug": "2.6.9", "depd": "2.0.0", @@ -1530,14 +1603,41 @@ } }, "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", + "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.18.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + } + } } }, "set-function-length": { diff --git a/package.json b/package.json index 7028c20..d8d2b2e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.19.2", + "express": "^4.20.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0", "express-prom-bundle": "^6.6.0" From e541281fa53e0ffc24c4498c2c10f6344f13fd99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 09:41:54 +0000 Subject: [PATCH 061/123] Bump send and express Bumps [send](https://github.com/pillarjs/send) to 0.19.0 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together. Updates `send` from 0.18.0 to 0.19.0 - [Release notes](https://github.com/pillarjs/send/releases) - [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md) - [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0) Updates `express` from 4.20.0 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.0) --- updated-dependencies: - dependency-name: send dependency-type: indirect - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 175 +++++++++++++++++----------------------------- package.json | 2 +- 2 files changed, 64 insertions(+), 113 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0fc6578..5a761a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.20.0", + "express": "^4.21.0", "express-prom-bundle": "^6.6.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" @@ -90,20 +90,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "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", @@ -281,9 +267,9 @@ } }, "node_modules/express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -297,7 +283,7 @@ "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", @@ -306,11 +292,11 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -345,12 +331,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -361,6 +347,14 @@ "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -714,11 +708,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -829,45 +823,25 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static/node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.8" } }, "node_modules/set-function-length": { @@ -1060,16 +1034,6 @@ "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" - }, - "dependencies": { - "qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "requires": { - "side-channel": "^1.0.6" - } - } } }, "buffer-equal-constant-time": { @@ -1203,9 +1167,9 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -1219,7 +1183,7 @@ "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", @@ -1228,11 +1192,11 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1257,17 +1221,24 @@ } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" + }, + "dependencies": { + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + } } }, "forwarded": { @@ -1524,11 +1495,11 @@ } }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "range-parser": { @@ -1603,40 +1574,20 @@ } }, "serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - } + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" } } }, diff --git a/package.json b/package.json index d8d2b2e..a9a26a3 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.20.0", + "express": "^4.21.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0", "express-prom-bundle": "^6.6.0" From 21bcdc7cfd0967bd08ab62dd078985df69b344f3 Mon Sep 17 00:00:00 2001 From: Dom Webber Date: Thu, 17 Oct 2024 17:37:56 +0100 Subject: [PATCH 062/123] Add error handling for JSON.parse Resolves https://github.com/mendhak/docker-http-https-echo/issues/73 --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index e22e3fa..efe71a6 100644 --- a/index.js +++ b/index.js @@ -105,7 +105,11 @@ app.all('*', (req, res) => { //If the Content-Type of the incoming body `is` JSON, it can be parsed and returned in the body if(req.is('application/json')){ - echo.json = JSON.parse(req.body) + try { + echo.json = JSON.parse(req.body) + } catch (error) { + console.warn("Invalid JSON Body received with Content-Type: application/json", error); + } } //If there's a JWT header, parse it and decode and put it in the response From 33314c12de8aa559317a44c3902a44bd8a605e20 Mon Sep 17 00:00:00 2001 From: Dom Webber Date: Sat, 19 Oct 2024 11:25:39 +0100 Subject: [PATCH 063/123] Add invalid JSON body test case --- tests.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests.sh b/tests.sh index 12cd8a4..ecb8785 100755 --- a/tests.sh +++ b/tests.sh @@ -155,6 +155,15 @@ else exit 1 fi +REQUEST=$(curl -s -X POST -H "Content-Type: application/json" -d 'not-json' http://localhost:8080) +if [ $(echo $REQUEST | jq -r '.json') == 'null' ]; then + passed "JSON with Invalid Body test passed." +else + failed "JSON with Invalid Body test failed." + echo $REQUEST | jq + exit 1 +fi + message " Stop containers " docker stop http-echo-tests sleep 5 From b2756756ee9319e5d6eec76998839b89f39b99ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:51:17 +0000 Subject: [PATCH 064/123] Bump cookie and express Bumps [cookie](https://github.com/jshttp/cookie) to 0.7.1 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together. Updates `cookie` from 0.6.0 to 0.7.1 - [Release notes](https://github.com/jshttp/cookie/releases) - [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1) Updates `express` from 4.21.0 to 4.21.1 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md) - [Commits](https://github.com/expressjs/express/compare/4.21.0...4.21.1) --- updated-dependencies: - dependency-name: cookie dependency-type: indirect - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a761a6..feb5976 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.21.0", + "express": "^4.21.1", "express-prom-bundle": "^6.6.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" @@ -160,9 +160,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -267,16 +267,16 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -1088,9 +1088,9 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, "cookie-signature": { "version": "1.0.6", @@ -1167,16 +1167,16 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", diff --git a/package.json b/package.json index a9a26a3..e028a3a 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.21.0", + "express": "^4.21.1", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0", "express-prom-bundle": "^6.6.0" From dc58452925ac60a1ae50d45954e6c44b8a950e67 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 19 Oct 2024 16:57:57 +0100 Subject: [PATCH 065/123] Update and changelog for v35 --- CHANGELOG.md | 8 +++++--- README.md | 30 +++++++++++++++--------------- docker-compose.yml | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 900adfb..f6b7554 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ +## Version `35` - 2024-10-19 +* Error handling for when invalid JSON body is passed in -## Version `34` - `2024-08-17` +## Version `34` - 2024-08-17 * Set `PRESERVE_HEADER_CASE` to `1` to attempt to preserve the case of headers in the response. * Set `OVERRIDE_RESPONSE_BODY_FILE_PATH` to a path, to override the response body with the contents of that file. -## Version `33` - `2024-04-07` +## Version `33` - 2024-04-07 * Implementing configurable CORS settings by [ash0ne](https://github.com/mendhak/docker-http-https-echo/pull/65). -## Version `32` - `2024-03-28` +## Version `32` - 2024-03-28 * Update Express to 4.19.2 to address CVE-2024-29041 ## Version `31` - 2023-12-03 diff --git a/README.md b/README.md index 5b2097d..17c39f5 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:34` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:34` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:35` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:35` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:34 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:35 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:34 + image: mendhak/http-https-echo:35 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:34 + image: mendhak/http-https-echo:35 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:34 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:35 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:34 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:35 ## Do not log specific path @@ -119,13 +119,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:34 + image: mendhak/http-https-echo:35 environment: - LOG_IGNORE_PATH=/ping ports: @@ -156,7 +156,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 ``` ## Send an empty response @@ -164,7 +164,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 ``` ## Custom status code @@ -245,7 +245,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:34 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:35 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -285,7 +285,7 @@ openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:34 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 ``` ## Override the response body with a file @@ -294,7 +294,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:34 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:35 ``` diff --git a/docker-compose.yml b/docker-compose.yml index 8ffda98..841094a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:34 + image: mendhak/http-https-echo:35 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 273d8ce70c7d4630354e5cdda6004e075918f319 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 23:01:25 +0000 Subject: [PATCH 066/123] Bump path-to-regexp and express Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.12 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together. Updates `path-to-regexp` from 0.1.10 to 0.1.12 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12) Updates `express` from 4.21.1 to 4.21.2 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md) - [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 34 +++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index feb5976..b47a953 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.21.1", + "express": "^4.21.2", "express-prom-bundle": "^6.6.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" @@ -267,9 +267,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -290,7 +290,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -305,6 +305,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-prom-bundle": { @@ -678,9 +682,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/prom-client": { "version": "15.1.1", @@ -1167,9 +1171,9 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -1190,7 +1194,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -1471,9 +1475,9 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "prom-client": { "version": "15.1.1", diff --git a/package.json b/package.json index e028a3a..972c979 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.21.1", + "express": "^4.21.2", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0", "express-prom-bundle": "^6.6.0" From c4520e1f3c7fea6d03f36967c4ee72a0df417f2f Mon Sep 17 00:00:00 2001 From: matt-mercer <449892+matt-mercer@users.noreply.github.com> Date: Wed, 19 Mar 2025 17:05:19 +0000 Subject: [PATCH 067/123] basic handling of gzip content-encoding on requests as per https://github.com/mendhak/docker-http-https-echo/issues/31 - new test added to tests.sh --- index.js | 10 ++++++++-- tests.sh | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index efe71a6..a380bea 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const express = require('express') const concat = require('concat-stream'); const { promisify } = require('util'); const promBundle = require("express-prom-bundle"); +const zlib = require("zlib"); const { PROMETHEUS_ENABLED = false, @@ -40,11 +41,16 @@ if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ app.use(function(req, res, next){ req.pipe(concat(function(data){ - req.body = data.toString('utf8'); + + if (req.get("Content-Encoding") === "gzip") { + req.body = zlib.gunzipSync(data).toString('utf8'); + } + else { + req.body = data.toString('utf8'); + } next(); })); }); - //Handle all paths app.all('*', (req, res) => { diff --git a/tests.sh b/tests.sh index ecb8785..d56f4e5 100755 --- a/tests.sh +++ b/tests.sh @@ -155,6 +155,18 @@ else exit 1 fi + +message " Make JSON request with gzip Content-Encoding, and test that json is in the output. " +REQUEST=$(echo -n '{"a":"b"}' | gzip | curl -s -X POST -H "Content-Encoding: gzip" -H "Content-Type: application/json" --data-binary @- http://localhost:8080/) +if [ $(echo $REQUEST | jq -r '.json.a') == 'b' ] +then + passed "JSON test passed." +else + failed "JSON test failed." + echo $REQUEST | jq + exit 1 +fi + REQUEST=$(curl -s -X POST -H "Content-Type: application/json" -d 'not-json' http://localhost:8080) if [ $(echo $REQUEST | jq -r '.json') == 'null' ]; then passed "JSON with Invalid Body test passed." From 10ed80b7f605cfa9ae4647594a8af28051c93b1a Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 22 Mar 2025 19:38:52 +0000 Subject: [PATCH 068/123] Update to latest node version and package versions --- Dockerfile | 2 +- package-lock.json | 1194 ++++++++++++--------------------------------- 2 files changed, 316 insertions(+), 880 deletions(-) diff --git a/Dockerfile b/Dockerfile index ed7a692..b998435 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine AS build +FROM node:22-alpine AS build WORKDIR /app COPY . /app diff --git a/package-lock.json b/package-lock.json index b47a953..daee106 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "@mendhak/http-https-echo", "version": "1.0.1", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -20,9 +20,10 @@ } }, "node_modules/@opentelemetry/api": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", - "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", "peer": true, "engines": { "node": ">=8.0.0" @@ -32,6 +33,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -43,12 +45,14 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -59,18 +63,21 @@ "node_modules/basic-auth/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/bintrees": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "license": "MIT", "peer": true }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -93,31 +100,45 @@ "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==" + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -133,6 +154,7 @@ "engines": [ "node >= 6.0" ], + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -144,6 +166,7 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -155,6 +178,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -163,6 +187,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -170,36 +195,23 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -208,15 +220,31 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "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" } @@ -224,23 +252,23 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -249,6 +277,19 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, "engines": { "node": ">= 0.4" } @@ -256,12 +297,14 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -270,6 +313,7 @@ "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -315,6 +359,7 @@ "version": "6.6.0", "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.6.0.tgz", "integrity": "sha512-tZh2P2p5a8/yxQ5VbRav011Poa4R0mHqdFwn9Swe/obXDe5F0jY9wtRAfNYnqk4LXY7akyvR/nrvAHxQPWUjsQ==", + "license": "MIT", "dependencies": { "on-finished": "^2.3.0", "url-value-parser": "^2.0.0" @@ -326,18 +371,11 @@ "prom-client": ">=12.0.0" } }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/finalhandler": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", @@ -351,18 +389,11 @@ "node": ">= 0.8" } }, - "node_modules/finalhandler/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -371,6 +402,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -379,20 +411,27 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -401,32 +440,24 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gopd": { + "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.4" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -435,9 +466,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -449,6 +481,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -460,6 +493,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -475,6 +509,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -485,25 +520,34 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "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": "^4.17.21", + "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.3.8" + "semver": "^7.5.4" }, "engines": { "node": ">=12", @@ -513,12 +557,14 @@ "node_modules/jsonwebtoken/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "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", @@ -529,31 +575,68 @@ "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/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, + "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.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/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" } }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -562,6 +645,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -570,6 +654,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -578,6 +663,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -589,6 +675,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -597,6 +684,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -608,6 +696,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -623,6 +712,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -633,20 +723,23 @@ "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -658,6 +751,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -669,6 +763,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -677,6 +772,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -684,12 +780,14 @@ "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" }, "node_modules/prom-client": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.1.tgz", - "integrity": "sha512-GVA2H96QCg2q71rjc3VYvSrVG7OpnJxyryC7dMzvfJfpJJHzQVwF3TJLfHzKORcwJpElWs1TwXLthlJAFJxq2A==", + "version": "15.1.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz", + "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==", + "license": "Apache-2.0", "peer": true, "dependencies": { "@opentelemetry/api": "^1.4.0", @@ -703,6 +801,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -715,6 +814,7 @@ "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" }, @@ -729,6 +829,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -737,6 +838,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -748,9 +850,10 @@ } }, "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -777,20 +880,20 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -802,6 +905,7 @@ "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -821,15 +925,26 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -840,44 +955,76 @@ "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -890,6 +1037,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -898,6 +1046,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -906,6 +1055,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "license": "MIT", "peer": true, "dependencies": { "bintrees": "1.0.2" @@ -915,6 +1065,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -923,6 +1074,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -934,12 +1086,14 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -948,6 +1102,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.2.0.tgz", "integrity": "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==", + "license": "MIT-0", "engines": { "node": ">=6.0.0" } @@ -955,12 +1110,14 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -969,731 +1126,10 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - }, - "dependencies": { - "@opentelemetry/api": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", - "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", - "peer": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "bintrees": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", - "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", - "peer": true - }, - "body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "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==" - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - } - }, - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - }, - "cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "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==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "requires": { - "get-intrinsic": "^1.2.4" - } - }, - "es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" - } - } - }, - "express-prom-bundle": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.6.0.tgz", - "integrity": "sha512-tZh2P2p5a8/yxQ5VbRav011Poa4R0mHqdFwn9Swe/obXDe5F0jY9wtRAfNYnqk4LXY7akyvR/nrvAHxQPWUjsQ==", - "requires": { - "on-finished": "^2.3.0", - "url-value-parser": "^2.0.0" - } - }, - "finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" - } - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - }, - "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "requires": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "requires": { - "es-define-property": "^1.0.0" - } - }, - "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "requires": { - "function-bind": "^1.1.2" - } - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", - "requires": { - "jws": "^3.2.2", - "lodash": "^4.17.21", - "ms": "^2.1.1", - "semver": "^7.3.8" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" - }, - "prom-client": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.1.tgz", - "integrity": "sha512-GVA2H96QCg2q71rjc3VYvSrVG7OpnJxyryC7dMzvfJfpJJHzQVwF3TJLfHzKORcwJpElWs1TwXLthlJAFJxq2A==", - "peer": true, - "requires": { - "@opentelemetry/api": "^1.4.0", - "tdigest": "^0.1.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "requires": { - "side-channel": "^1.0.6" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "requires": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "dependencies": { - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" - } - } - }, - "set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "requires": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "requires": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "tdigest": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", - "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", - "peer": true, - "requires": { - "bintrees": "1.0.2" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "url-value-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.2.0.tgz", - "integrity": "sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } From aa7e9f2277511b415de74a8621681b86fe63ce26 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 22 Mar 2025 19:52:12 +0000 Subject: [PATCH 069/123] Update to latest node version and package versions --- Dockerfile | 2 +- package-lock.json | 115 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 4 +- 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index b998435..6e7cc65 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN set -ex \ && chown -R node:node /app \ && chmod +r /app/privkey.pem -FROM node:18-alpine AS final +FROM node:22-alpine AS final LABEL \ org.opencontainers.image.title="http-https-echo" \ org.opencontainers.image.description="Docker image that echoes request data as JSON; listens on HTTP/S, with various extra features, useful for debugging." \ diff --git a/package-lock.json b/package-lock.json index daee106..984dfe8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "concat-stream": "^2.0.0", "express": "^4.21.2", - "express-prom-bundle": "^6.6.0", + "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.0" }, @@ -29,6 +29,102 @@ "node": ">=8.0.0" } }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz", + "integrity": "sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.13.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz", + "integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/qs": { + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -356,19 +452,20 @@ } }, "node_modules/express-prom-bundle": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.6.0.tgz", - "integrity": "sha512-tZh2P2p5a8/yxQ5VbRav011Poa4R0mHqdFwn9Swe/obXDe5F0jY9wtRAfNYnqk4LXY7akyvR/nrvAHxQPWUjsQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-8.0.0.tgz", + "integrity": "sha512-UHdpaMks6Z/tvxQsNzhsE7nkdXb4/zEh/jwN0tfZSZOEF+aD0dlfl085EU4jveOq09v01c5sIUfjV4kJODZ2eQ==", "license": "MIT", "dependencies": { + "@types/express": "^5.0.0", "on-finished": "^2.3.0", "url-value-parser": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "prom-client": ">=12.0.0" + "prom-client": ">=15.0.0" } }, "node_modules/finalhandler": { @@ -1089,6 +1186,12 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index 972c979..82f679e 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "dependencies": { "concat-stream": "^2.0.0", "express": "^4.21.2", + "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", - "morgan": "^1.10.0", - "express-prom-bundle": "^6.6.0" + "morgan": "^1.10.0" } } From ae664c635c75a2ae5900d2ced9f4d20330261fb4 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 22 Mar 2025 20:00:47 +0000 Subject: [PATCH 070/123] Changelog update --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6b7554..ac11269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `36` - 2025-03-22 +* Basic handling of gzip content-encoding on requests by [matt-mercer](https://github.com/mendhak/docker-http-https-echo/pull/79) + ## Version `35` - 2024-10-19 * Error handling for when invalid JSON body is passed in From 1ed4408ed0e4995b645af565e7b4be7712c663a7 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 22 Mar 2025 20:12:44 +0000 Subject: [PATCH 071/123] There is no node image for ppc64le, so removing it from publish --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3cf30d4..79c1758 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,7 +53,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From ced76926d3eca3a56f36c210bdb6ddaffbcc9a2a Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 22 Mar 2025 20:16:39 +0000 Subject: [PATCH 072/123] Replace references to latest tag --- README.md | 30 +++++++++++++++--------------- docker-compose.yml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 17c39f5..879b4c2 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:35` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:35` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:36` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:36` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:35 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:36 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:35 + image: mendhak/http-https-echo:36 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:35 + image: mendhak/http-https-echo:36 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:35 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:36 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:35 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 ## Do not log specific path @@ -119,13 +119,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:35 + image: mendhak/http-https-echo:36 environment: - LOG_IGNORE_PATH=/ping ports: @@ -156,7 +156,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 ``` ## Send an empty response @@ -164,7 +164,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 ``` ## Custom status code @@ -245,7 +245,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:35 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -285,7 +285,7 @@ openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:35 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 ``` ## Override the response body with a file @@ -294,7 +294,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:35 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:36 ``` diff --git a/docker-compose.yml b/docker-compose.yml index 841094a..c0728a5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:35 + image: mendhak/http-https-echo:36 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From bc3afb285b7f8522c2f0b43793ec853484d87723 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 10 May 2025 22:24:16 +0100 Subject: [PATCH 073/123] log_ignore_path env var now takes a regex --- index.js | 2 +- tests.sh | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index a380bea..5bb7894 100644 --- a/index.js +++ b/index.js @@ -175,7 +175,7 @@ app.all('*', (req, res) => { } //Certain paths can be ignored in the container logs, useful to reduce noise from healthchecks - if (process.env.LOG_IGNORE_PATH != req.path) { + if (!process.env.LOG_IGNORE_PATH || !new RegExp(process.env.LOG_IGNORE_PATH).test(req.path)) { let spacer = 4; if(process.env.LOG_WITHOUT_NEWLINE){ diff --git a/tests.sh b/tests.sh index d56f4e5..d26886d 100755 --- a/tests.sh +++ b/tests.sh @@ -270,7 +270,7 @@ docker stop http-echo-tests sleep 5 -message " Start container with LOG_IGNORE_PATH " +message " Start container with LOG_IGNORE_PATH (normal path)" docker run -d --rm -e LOG_IGNORE_PATH=/ping --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 curl -s -k -X POST -d "banana" https://localhost:8443/ping > /dev/null @@ -285,6 +285,38 @@ else exit 1 fi +message " Stop containers " +docker stop http-echo-tests +sleep 5 + +message " Start container with LOG_IGNORE_PATH (regex path)" +docker run -d --rm -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +sleep 5 +curl -s -k -X POST -d "banana" https://localhost:8443/metrics > /dev/null + +if [ $(docker logs http-echo-tests | wc -l) == 2 ] && \ + ! [ $(docker logs http-echo-tests | grep banana) ] +then + passed "LOG_IGNORE_PATH ignored the /metrics path" +else + failed "LOG_IGNORE_PATH failed" + docker logs http-echo-tests + exit 1 +fi + +# Test a positive case where the path is not ignored +curl -s -k -X POST -d "strawberry" https://localhost:8443/veryvisible > /dev/null + +if [[ $(docker logs http-echo-tests | grep strawberry) ]] +then + passed "LOG_IGNORE_PATH didn't ignore the /veryvisible path" +else + failed "LOG_IGNORE_PATH failed, it should not ignore the /veryvisible path" + docker logs http-echo-tests + exit 1 +fi + + message " Stop containers " docker stop http-echo-tests From a1d80f77235dc5781a570c65ff01d23194b78287 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 10 May 2025 22:26:04 +0100 Subject: [PATCH 074/123] Update README with regex example for log ignore path --- README.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 879b4c2..ab2a7c5 100644 --- a/README.md +++ b/README.md @@ -116,22 +116,13 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t ## Do not log specific path -Set the environment variable `LOG_IGNORE_PATH` to a path you would like to exclude from verbose logging to stdout. +Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 -With docker compose, this would be: - - my-http-listener: - image: mendhak/http-https-echo:36 - environment: - - LOG_IGNORE_PATH=/ping - ports: - - "8080:8080" - - "8443:8443" - ## JSON payloads and JSON output From fad4c1187385ca682b68d6dad8d415dd67ae0f7b Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 10 May 2025 22:26:51 +0100 Subject: [PATCH 075/123] Changelog for 37 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac11269..2cf5398 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `37` - 2025-05-10 +* The `LOG_IGNORE_PATH` environment variable now takes a regex, so you can ignore multiple paths. + ## Version `36` - 2025-03-22 * Basic handling of gzip content-encoding on requests by [matt-mercer](https://github.com/mendhak/docker-http-https-echo/pull/79) From 1b948fda56d54a3e5e24fecb3a2e38ce2941f84c Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 10 May 2025 22:39:51 +0100 Subject: [PATCH 076/123] Test to ignore all paths --- tests.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests.sh b/tests.sh index d26886d..ce94ef0 100755 --- a/tests.sh +++ b/tests.sh @@ -317,11 +317,30 @@ else fi +message " Stop containers " +docker stop http-echo-tests +sleep 5 + +message " Start container with LOG_IGNORE_PATH (ignore all paths) " +docker run -d --rm -e LOG_IGNORE_PATH=".*" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +sleep 5 +curl -s -k -X POST -d "banana" https://localhost:8443/ > /dev/null + +if [ $(docker logs http-echo-tests | wc -l) == 2 ] && \ + ! [ $(docker logs http-echo-tests | grep banana) ] +then + passed "LOG_IGNORE_PATH ignored all paths" +else + failed "LOG_IGNORE_PATH failed" + docker logs http-echo-tests + exit 1 +fi message " Stop containers " docker stop http-echo-tests sleep 5 + message " Start container with DISABLE_REQUEST_LOGS " docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 From fa983b906ec7ea953af70702d56b9b1081357141 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 10 May 2025 22:40:11 +0100 Subject: [PATCH 077/123] README example for ignoring all paths --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab2a7c5..5a921bb 100644 --- a/README.md +++ b/README.md @@ -119,8 +119,12 @@ In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, t Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would like to exclude from verbose logging to stdout. This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 - docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 + # Ignore a single path + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 + # Ignore multiple paths + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 + # Ignore all paths + docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 From 7bd456a55209adfb060a9a02cfa0a1c60714ce5f Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 10 May 2025 22:58:27 +0100 Subject: [PATCH 078/123] Updating references to tag 37 in preparation for release later --- README.md | 32 ++++++++++++++++---------------- docker-compose.yml | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5a921bb..a55102a 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:36` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:36` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:37` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:37` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:36 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:37 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:36 + image: mendhak/http-https-echo:37 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:36 + image: mendhak/http-https-echo:37 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:36 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:37 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 ## Do not log specific path @@ -120,11 +120,11 @@ Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would li This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. # Ignore a single path - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 # Ignore multiple paths - docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 # Ignore all paths - docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 + docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 @@ -151,7 +151,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 ``` ## Send an empty response @@ -159,7 +159,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 ``` ## Custom status code @@ -240,7 +240,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:36 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -280,7 +280,7 @@ openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:36 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 ``` ## Override the response body with a file @@ -289,7 +289,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:36 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:37 ``` diff --git a/docker-compose.yml b/docker-compose.yml index c0728a5..9504585 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:36 + image: mendhak/http-https-echo:37 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 99fcbce68fd51d234386bfde1504cb3542dd935e Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 22 May 2025 21:13:40 +0100 Subject: [PATCH 079/123] another way to ignore all paths --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a55102a..65ba6b2 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ This can help reduce noise from healthchecks in orchestration/infrastructure lik docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 # Ignore all paths docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 + docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 From 683367e68692b5b06018e95f0b626a41f1698cf9 Mon Sep 17 00:00:00 2001 From: Matthias Koch Date: Thu, 23 Oct 2025 19:25:18 +0200 Subject: [PATCH 080/123] Add maxHeaderSize --- index.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 5bb7894..7d3ef78 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,7 @@ const { PROMETHEUS_WITH_METHOD = 'true', PROMETHEUS_WITH_STATUS = 'true', PROMETHEUS_METRIC_TYPE = 'summary', + MAX_HEADER_SIZE = 1048576 } = process.env const sleep = promisify(setTimeout); @@ -189,22 +190,27 @@ app.all('*', (req, res) => { }); -let sslOpts = { +let httpOpts = { + maxHeaderSize: process.env.MAX_HEADER_SIZE +} + +let httpsOpts = { key: require('fs').readFileSync(process.env.HTTPS_KEY_FILE || 'privkey.pem'), - cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem') + cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem'), + maxHeaderSize: process.env.MAX_HEADER_SIZE }; //Whether to enable the client certificate feature if(process.env.MTLS_ENABLE){ - sslOpts = { + httpsOpts = { requestCert: true, rejectUnauthorized: false, - ...sslOpts + ...httpsOpts } } -var httpServer = http.createServer(app).listen(process.env.HTTP_PORT || 8080); -var httpsServer = https.createServer(sslOpts,app).listen(process.env.HTTPS_PORT || 8443); +var httpServer = http.createServer(httpOpts, app).listen(process.env.HTTP_PORT || 8080); +var httpsServer = https.createServer(httpsOpts,app).listen(process.env.HTTPS_PORT || 8443); console.log(`Listening on ports ${process.env.HTTP_PORT || 8080} for http, and ${process.env.HTTPS_PORT || 8443} for https.`); let calledClose = false; From 28b0e99cb5457560286876f13aeee28d8ffd115b Mon Sep 17 00:00:00 2001 From: Matthias Koch Date: Thu, 23 Oct 2025 19:26:43 +0200 Subject: [PATCH 081/123] Refactor index.js for improved readability and consistency --- index.js | 58 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index 7d3ef78..8ebb2c5 100644 --- a/index.js +++ b/index.js @@ -32,16 +32,16 @@ const app = express() app.set('json spaces', 2); app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); -if(PROMETHEUS_ENABLED === 'true') { +if (PROMETHEUS_ENABLED === 'true') { app.use(metricsMiddleware); } -if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ +if (process.env.DISABLE_REQUEST_LOGS !== 'true') { app.use(morgan('combined')); } -app.use(function(req, res, next){ - req.pipe(concat(function(data){ +app.use(function (req, res, next) { + req.pipe(concat(function (data) { if (req.get("Content-Encoding") === "gzip") { req.body = zlib.gunzipSync(data).toString('utf8'); @@ -54,10 +54,10 @@ app.use(function(req, res, next){ }); //Handle all paths app.all('*', (req, res) => { - - if(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH){ + + if (process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH) { // Path is relative to current directory - res.sendFile(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH, { root : __dirname}); + res.sendFile(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH, { root: __dirname }); return; } @@ -83,35 +83,35 @@ app.all('*', (req, res) => { } }; - if(process.env.PRESERVE_HEADER_CASE){ - let newHeaders = {...req.headers}; + if (process.env.PRESERVE_HEADER_CASE) { + let newHeaders = { ...req.headers }; // req.headers is in lowercase, processed, deduplicated. req.rawHeaders is not. // Match on the preserved case of the header name, populate newHeaders with preserved case and processed value. for (let i = 0; i < req.rawHeaders.length; i += 2) { let preservedHeaderName = req.rawHeaders[i]; if (preservedHeaderName == preservedHeaderName.toLowerCase()) { continue; } - + newHeaders[preservedHeaderName] = req.header(preservedHeaderName); delete newHeaders[preservedHeaderName.toLowerCase()]; } echo.headers = newHeaders; } - + //Add client certificate details to the output, if present //This only works if `requestCert` is true when starting the server. - if(req.socket.getPeerCertificate){ + if (req.socket.getPeerCertificate) { echo.clientCertificate = req.socket.getPeerCertificate(); } //Include visible environment variables - if(process.env.ECHO_INCLUDE_ENV_VARS){ + if (process.env.ECHO_INCLUDE_ENV_VARS) { echo.env = process.env; } //If the Content-Type of the incoming body `is` JSON, it can be parsed and returned in the body - if(req.is('application/json')){ + if (req.is('application/json')) { try { echo.json = JSON.parse(req.body) } catch (error) { @@ -126,7 +126,7 @@ app.all('*', (req, res) => { echo.jwt = token; } else { token = token.split(" ").pop(); - const decoded = jwt.decode(token, {complete: true}); + const decoded = jwt.decode(token, { complete: true }); echo.jwt = decoded; } } @@ -144,12 +144,12 @@ app.all('*', (req, res) => { //Set the response content type to what the user wants const setResponseContentType = req.headers["x-set-response-content-type"] || req.query["x-set-response-content-type"]; - if(setResponseContentType){ + if (setResponseContentType) { res.contentType(setResponseContentType); } //Set the CORS policy - if (process.env.CORS_ALLOW_ORIGIN){ + if (process.env.CORS_ALLOW_ORIGIN) { res.header('Access-Control-Allow-Origin', process.env.CORS_ALLOW_ORIGIN); if (process.env.CORS_ALLOW_METHODS) { res.header('Access-Control-Allow-Methods', process.env.CORS_ALLOW_METHODS); @@ -163,7 +163,7 @@ app.all('*', (req, res) => { } //Ability to send an empty response back - if (process.env.ECHO_BACK_TO_CLIENT != undefined && process.env.ECHO_BACK_TO_CLIENT == "false"){ + if (process.env.ECHO_BACK_TO_CLIENT != undefined && process.env.ECHO_BACK_TO_CLIENT == "false") { res.end(); } //Ability to send just the request body in the response, nothing else @@ -179,7 +179,7 @@ app.all('*', (req, res) => { if (!process.env.LOG_IGNORE_PATH || !new RegExp(process.env.LOG_IGNORE_PATH).test(req.path)) { let spacer = 4; - if(process.env.LOG_WITHOUT_NEWLINE){ + if (process.env.LOG_WITHOUT_NEWLINE) { spacer = null; } @@ -201,16 +201,16 @@ let httpsOpts = { }; //Whether to enable the client certificate feature -if(process.env.MTLS_ENABLE){ +if (process.env.MTLS_ENABLE) { httpsOpts = { - requestCert: true, - rejectUnauthorized: false, - ...httpsOpts - } + requestCert: true, + rejectUnauthorized: false, + ...httpsOpts + } } var httpServer = http.createServer(httpOpts, app).listen(process.env.HTTP_PORT || 8080); -var httpsServer = https.createServer(httpsOpts,app).listen(process.env.HTTPS_PORT || 8443); +var httpsServer = https.createServer(httpsOpts, app).listen(process.env.HTTPS_PORT || 8443); console.log(`Listening on ports ${process.env.HTTP_PORT || 8080} for http, and ${process.env.HTTPS_PORT || 8443} for https.`); let calledClose = false; @@ -218,7 +218,7 @@ let calledClose = false; process.on('exit', function () { if (calledClose) return; console.log('Got exit event. Trying to stop Express server.'); - server.close(function() { + server.close(function () { console.log("Express server closed"); }); }); @@ -226,11 +226,11 @@ process.on('exit', function () { process.on('SIGINT', shutDown); process.on('SIGTERM', shutDown); -function shutDown(){ +function shutDown() { console.log('Got a kill signal. Trying to exit gracefully.'); calledClose = true; - httpServer.close(function() { - httpsServer.close(function() { + httpServer.close(function () { + httpsServer.close(function () { console.log("HTTP and HTTPS servers closed. Asking process to exit."); process.exit() }); From 098fbf8013b006f1e4121da56ced3bbfeaace163 Mon Sep 17 00:00:00 2001 From: Matthias Koch Date: Thu, 23 Oct 2025 19:28:09 +0200 Subject: [PATCH 082/123] Revert format --- index.js | 60 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index 8ebb2c5..760a327 100644 --- a/index.js +++ b/index.js @@ -32,16 +32,16 @@ const app = express() app.set('json spaces', 2); app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); -if (PROMETHEUS_ENABLED === 'true') { +if(PROMETHEUS_ENABLED === 'true') { app.use(metricsMiddleware); } -if (process.env.DISABLE_REQUEST_LOGS !== 'true') { +if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ app.use(morgan('combined')); } -app.use(function (req, res, next) { - req.pipe(concat(function (data) { +app.use(function(req, res, next){ + req.pipe(concat(function(data){ if (req.get("Content-Encoding") === "gzip") { req.body = zlib.gunzipSync(data).toString('utf8'); @@ -54,10 +54,10 @@ app.use(function (req, res, next) { }); //Handle all paths app.all('*', (req, res) => { - - if (process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH) { + + if(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH){ // Path is relative to current directory - res.sendFile(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH, { root: __dirname }); + res.sendFile(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH, { root : __dirname}); return; } @@ -83,35 +83,35 @@ app.all('*', (req, res) => { } }; - if (process.env.PRESERVE_HEADER_CASE) { - let newHeaders = { ...req.headers }; + if(process.env.PRESERVE_HEADER_CASE){ + let newHeaders = {...req.headers}; // req.headers is in lowercase, processed, deduplicated. req.rawHeaders is not. // Match on the preserved case of the header name, populate newHeaders with preserved case and processed value. for (let i = 0; i < req.rawHeaders.length; i += 2) { let preservedHeaderName = req.rawHeaders[i]; if (preservedHeaderName == preservedHeaderName.toLowerCase()) { continue; } - + newHeaders[preservedHeaderName] = req.header(preservedHeaderName); delete newHeaders[preservedHeaderName.toLowerCase()]; } echo.headers = newHeaders; } - + //Add client certificate details to the output, if present //This only works if `requestCert` is true when starting the server. - if (req.socket.getPeerCertificate) { + if(req.socket.getPeerCertificate){ echo.clientCertificate = req.socket.getPeerCertificate(); } //Include visible environment variables - if (process.env.ECHO_INCLUDE_ENV_VARS) { + if(process.env.ECHO_INCLUDE_ENV_VARS){ echo.env = process.env; } //If the Content-Type of the incoming body `is` JSON, it can be parsed and returned in the body - if (req.is('application/json')) { + if(req.is('application/json')){ try { echo.json = JSON.parse(req.body) } catch (error) { @@ -126,7 +126,7 @@ app.all('*', (req, res) => { echo.jwt = token; } else { token = token.split(" ").pop(); - const decoded = jwt.decode(token, { complete: true }); + const decoded = jwt.decode(token, {complete: true}); echo.jwt = decoded; } } @@ -144,12 +144,12 @@ app.all('*', (req, res) => { //Set the response content type to what the user wants const setResponseContentType = req.headers["x-set-response-content-type"] || req.query["x-set-response-content-type"]; - if (setResponseContentType) { + if(setResponseContentType){ res.contentType(setResponseContentType); } //Set the CORS policy - if (process.env.CORS_ALLOW_ORIGIN) { + if (process.env.CORS_ALLOW_ORIGIN){ res.header('Access-Control-Allow-Origin', process.env.CORS_ALLOW_ORIGIN); if (process.env.CORS_ALLOW_METHODS) { res.header('Access-Control-Allow-Methods', process.env.CORS_ALLOW_METHODS); @@ -163,7 +163,7 @@ app.all('*', (req, res) => { } //Ability to send an empty response back - if (process.env.ECHO_BACK_TO_CLIENT != undefined && process.env.ECHO_BACK_TO_CLIENT == "false") { + if (process.env.ECHO_BACK_TO_CLIENT != undefined && process.env.ECHO_BACK_TO_CLIENT == "false"){ res.end(); } //Ability to send just the request body in the response, nothing else @@ -179,7 +179,7 @@ app.all('*', (req, res) => { if (!process.env.LOG_IGNORE_PATH || !new RegExp(process.env.LOG_IGNORE_PATH).test(req.path)) { let spacer = 4; - if (process.env.LOG_WITHOUT_NEWLINE) { + if(process.env.LOG_WITHOUT_NEWLINE){ spacer = null; } @@ -201,16 +201,16 @@ let httpsOpts = { }; //Whether to enable the client certificate feature -if (process.env.MTLS_ENABLE) { - httpsOpts = { - requestCert: true, - rejectUnauthorized: false, - ...httpsOpts - } +if(process.env.MTLS_ENABLE){ + httpsOpts = { + requestCert: true, + rejectUnauthorized: false, + ...httpsOpts + } } var httpServer = http.createServer(httpOpts, app).listen(process.env.HTTP_PORT || 8080); -var httpsServer = https.createServer(httpsOpts, app).listen(process.env.HTTPS_PORT || 8443); +var httpsServer = https.createServer(httpsOpts,app).listen(process.env.HTTPS_PORT || 8443); console.log(`Listening on ports ${process.env.HTTP_PORT || 8080} for http, and ${process.env.HTTPS_PORT || 8443} for https.`); let calledClose = false; @@ -218,7 +218,7 @@ let calledClose = false; process.on('exit', function () { if (calledClose) return; console.log('Got exit event. Trying to stop Express server.'); - server.close(function () { + server.close(function() { console.log("Express server closed"); }); }); @@ -226,11 +226,11 @@ process.on('exit', function () { process.on('SIGINT', shutDown); process.on('SIGTERM', shutDown); -function shutDown() { +function shutDown(){ console.log('Got a kill signal. Trying to exit gracefully.'); calledClose = true; - httpServer.close(function () { - httpsServer.close(function () { + httpServer.close(function() { + httpsServer.close(function() { console.log("HTTP and HTTPS servers closed. Asking process to exit."); process.exit() }); From f72db68aa44bdb19ba036eca691b628e6be04cb5 Mon Sep 17 00:00:00 2001 From: Matthias Koch Date: Thu, 23 Oct 2025 19:42:04 +0200 Subject: [PATCH 083/123] Implement large header request test in tests.sh Added a test for handling large headers in requests. --- tests.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests.sh b/tests.sh index ce94ef0..056f1c4 100755 --- a/tests.sh +++ b/tests.sh @@ -176,6 +176,17 @@ else exit 1 fi +message " Make request with a large header." +LARGE_HEADER_VALUE=$(head -c 10000 Date: Thu, 23 Oct 2025 19:43:57 +0200 Subject: [PATCH 084/123] Replace process.env.MAX_HEADER_SIZE with MAX_HEADER_SIZE --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 760a327..2041572 100644 --- a/index.js +++ b/index.js @@ -191,13 +191,13 @@ app.all('*', (req, res) => { }); let httpOpts = { - maxHeaderSize: process.env.MAX_HEADER_SIZE + maxHeaderSize: MAX_HEADER_SIZE } let httpsOpts = { key: require('fs').readFileSync(process.env.HTTPS_KEY_FILE || 'privkey.pem'), cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem'), - maxHeaderSize: process.env.MAX_HEADER_SIZE + maxHeaderSize: MAX_HEADER_SIZE }; //Whether to enable the client certificate feature From 693d587b7e3f076d00d39bcedc951b57b570d484 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 24 Oct 2025 21:21:20 +0100 Subject: [PATCH 085/123] Parse the max header env variable as an int to use --- index.js | 7 +++++-- tests.sh | 25 +++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 2041572..eba6fba 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,9 @@ const { MAX_HEADER_SIZE = 1048576 } = process.env +const maxHeaderSize = parseInt(MAX_HEADER_SIZE, 10) || 1048576; + + const sleep = promisify(setTimeout); const metricsMiddleware = promBundle({ metricsPath: PROMETHEUS_METRICS_PATH, @@ -191,13 +194,13 @@ app.all('*', (req, res) => { }); let httpOpts = { - maxHeaderSize: MAX_HEADER_SIZE + maxHeaderSize: maxHeaderSize } let httpsOpts = { key: require('fs').readFileSync(process.env.HTTPS_KEY_FILE || 'privkey.pem'), cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem'), - maxHeaderSize: MAX_HEADER_SIZE + maxHeaderSize: maxHeaderSize }; //Whether to enable the client certificate feature diff --git a/tests.sh b/tests.sh index 056f1c4..1262fe7 100755 --- a/tests.sh +++ b/tests.sh @@ -176,9 +176,18 @@ else exit 1 fi -message " Make request with a large header." -LARGE_HEADER_VALUE=$(head -c 10000 &1) +if echo $REQUEST | grep -q "HTTP/1.1 431 Request Header Fields Too Large"; then + passed "Large header test resulted in HTTP 431." +else + failed "Large header test failed." + echo $REQUEST + exit 1 +fi + message " Stop containers " docker stop http-echo-tests sleep 5 From 48058be151092875223fb6115d3d766819f275ed Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 24 Oct 2025 21:22:58 +0100 Subject: [PATCH 086/123] Update README instructions --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 65ba6b2..3eef55e 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,14 @@ The file path needs to be in the `/app` directory. docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:37 ``` +## Set a maximum header size + +You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header size in bytes. The default is 1MB. + +```bash +docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 +``` + ## Prometheus Metrics @@ -323,7 +331,7 @@ You can configure these metrics using the following variables: -## Building +## Building and developing locally docker build -t mendhak/http-https-echo . From b9ce5fa271f8631b48131d00897b19a0a915687d Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 24 Oct 2025 21:31:55 +0100 Subject: [PATCH 087/123] Add v38 note --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cf5398..dd22065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `38` - 2025-10-24 +* Add a `MAX_HEADER_SIZE` environment variable to set the maximum header size. The default is 1MB. + ## Version `37` - 2025-05-10 * The `LOG_IGNORE_PATH` environment variable now takes a regex, so you can ignore multiple paths. From b44dc319b43ae322a30db3066d4293bd529e2cf4 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 24 Oct 2025 21:38:32 +0100 Subject: [PATCH 088/123] Replace references to :38 --- README.md | 36 ++++++++++++++++++------------------ docker-compose.yml | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 3eef55e..4f0eebc 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:37` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:37` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:38` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:38` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:37 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:38 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:37 + image: mendhak/http-https-echo:38 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:37 + image: mendhak/http-https-echo:38 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:37 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:38 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 ## Do not log specific path @@ -120,12 +120,12 @@ Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would li This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. # Ignore a single path - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 # Ignore multiple paths - docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 # Ignore all paths - docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 - docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 + docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 + docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 @@ -152,7 +152,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 ``` ## Send an empty response @@ -160,7 +160,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 ``` ## Custom status code @@ -241,7 +241,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -281,7 +281,7 @@ openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:37 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 ``` ## Override the response body with a file @@ -290,7 +290,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:37 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:38 ``` ## Set a maximum header size @@ -298,7 +298,7 @@ docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_R You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header size in bytes. The default is 1MB. ```bash -docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:37 +docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 ``` diff --git a/docker-compose.yml b/docker-compose.yml index 9504585..971e7e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:37 + image: mendhak/http-https-echo:38 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From a60a97d9a19cfbf205b4c04a8307b22e35c168fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 20:41:28 +0000 Subject: [PATCH 089/123] Bump on-headers and morgan Bumps [on-headers](https://github.com/jshttp/on-headers) to 1.1.0 and updates ancestor dependency [morgan](https://github.com/expressjs/morgan). These dependencies need to be updated together. Updates `on-headers` from 1.0.2 to 1.1.0 - [Release notes](https://github.com/jshttp/on-headers/releases) - [Changelog](https://github.com/jshttp/on-headers/blob/master/HISTORY.md) - [Commits](https://github.com/jshttp/on-headers/compare/v1.0.2...v1.1.0) Updates `morgan` from 1.10.0 to 1.10.1 - [Release notes](https://github.com/expressjs/morgan/releases) - [Changelog](https://github.com/expressjs/morgan/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/morgan/compare/1.10.0...1.10.1) --- updated-dependencies: - dependency-name: on-headers dependency-version: 1.1.0 dependency-type: indirect - dependency-name: morgan dependency-version: 1.10.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 984dfe8..794dcbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "express": "^4.21.2", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", - "morgan": "^1.10.0" + "morgan": "^1.10.1" }, "engines": { "node": ">=16.0.0" @@ -790,16 +790,16 @@ } }, "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" @@ -857,9 +857,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", "engines": { "node": ">= 0.8" diff --git a/package.json b/package.json index 82f679e..006bfc5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,6 @@ "express": "^4.21.2", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", - "morgan": "^1.10.0" + "morgan": "^1.10.1" } } From 82631d36133625ba751a58b1951e358674b4f9b3 Mon Sep 17 00:00:00 2001 From: Willy Guggenheim <10598011+willyguggenheim@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:06:27 -0800 Subject: [PATCH 090/123] Smaller Runtime Image & Solve CVE-2025-64756 Remove unnecessary global node modules to reduce image size. Solve CVE-2025-64756 found in base image within unused `node_modules` tooling folder (not used in runtime image). --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 6e7cc65..5fa2048 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,7 @@ LABEL \ org.opencontainers.image.source="https://github.com/mendhak/docker-http-https-echo" \ org.opencontainers.image.licenses="MIT" WORKDIR /app +RUN rm -rf /usr/local/lib/node_modules COPY --from=build /app /app ENV HTTP_PORT=8080 HTTPS_PORT=8443 EXPOSE $HTTP_PORT $HTTPS_PORT From 56c2e0f75aac98dc8a70c430ae15c7df9273c0cb Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 21 Nov 2025 10:39:21 +0000 Subject: [PATCH 091/123] Begin the changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd22065..6c9eb98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `39` - 2025-11-21 +* Removed `/usr/local/lib/node_modules` from image to reduce CVE footprint + ## Version `38` - 2025-10-24 * Add a `MAX_HEADER_SIZE` environment variable to set the maximum header size. The default is 1MB. From c94de3c8f57ebf70dd1afc48d8d80e0182873a38 Mon Sep 17 00:00:00 2001 From: Willy Guggenheim Date: Thu, 8 Jan 2026 19:01:09 -0800 Subject: [PATCH 092/123] Fix security vulnerabilities and improve LOG_IGNORE_PATH - Update express to ^4.22.0 to fix body-parser and qs vulnerabilities - Add npm override for jws ^3.2.3 to fix CVE-2025-65945 - Generate SSL certificates in memory at runtime instead of build time to avoid storing private keys in the Docker image - Make LOG_IGNORE_PATH also skip Morgan HTTP access logs, not just the JSON echo output - Update LOG_WITHOUT_NEWLINE test to expect 4 log lines (includes the certificate generation message) --- Dockerfile | 10 +- index.js | 218 ++++++++++++++++++++++++++++++++++++++- package-lock.json | 257 ++++++++++++++++++++++------------------------ package.json | 5 +- tests.sh | 2 +- 5 files changed, 343 insertions(+), 149 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5fa2048..8ceaaa3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,18 +6,10 @@ COPY . /app RUN set -ex \ # Build JS-Application && npm install --production \ - # Generate SSL-certificate (for HTTPS) - && apk --no-cache add openssl \ - && openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout privkey.pem -out fullchain.pem \ - -subj "/C=GB/ST=London/L=London/O=Mendhak/CN=my.example.com" \ - -addext "subjectAltName=DNS:my.example.com,DNS:my.example.net,IP:192.168.50.108,IP:127.0.0.1" \ - && apk del openssl \ - && rm -rf /var/cache/apk/* \ # Delete unnecessary files && rm package* \ # Correct User's file access - && chown -R node:node /app \ - && chmod +r /app/privkey.pem + && chown -R node:node /app FROM node:22-alpine AS final LABEL \ diff --git a/index.js b/index.js index eba6fba..d43cba9 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,6 @@ const os = require('os'); +const fs = require('fs'); +const crypto = require('crypto'); const jwt = require('jsonwebtoken'); const http = require('http') const https = require('https') @@ -9,6 +11,207 @@ const { promisify } = require('util'); const promBundle = require("express-prom-bundle"); const zlib = require("zlib"); +// Get HTTPS credentials - either from files or generate self-signed in memory +function getHttpsCredentials() { + const keyFile = process.env.HTTPS_KEY_FILE; + const certFile = process.env.HTTPS_CERT_FILE; + + // If both files are specified and exist, use them + if (keyFile && certFile) { + try { + return { + key: fs.readFileSync(keyFile), + cert: fs.readFileSync(certFile) + }; + } catch (err) { + console.log(`Could not read cert files (${err.message}), generating self-signed certificate...`); + } + } + + // Try default file locations for backward compatibility + try { + return { + key: fs.readFileSync('privkey.pem'), + cert: fs.readFileSync('fullchain.pem') + }; + } catch (err) { + // Generate self-signed certificate in memory + console.log('Generating self-signed certificate in memory...'); + return generateSelfSignedCertificate(); + } +} + +// Generate a self-signed certificate entirely in memory +function generateSelfSignedCertificate() { + const { privateKey } = crypto.generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: { type: 'spki', format: 'pem' }, + privateKeyEncoding: { type: 'pkcs8', format: 'pem' } + }); + + const publicKey = crypto.createPublicKey(crypto.createPrivateKey(privateKey)); + + // Get the public key in DER format for the certificate + const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' }); + + // Create certificate structure + const serialNumber = crypto.randomBytes(8); + const now = new Date(); + const notBefore = now; + const notAfter = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000); + + // Build ASN.1 TBSCertificate + const tbsCert = buildTBSCertificate(serialNumber, notBefore, notAfter, publicKeyDer); + + // Sign the TBSCertificate + const sign = crypto.createSign('SHA256'); + sign.update(tbsCert); + const signature = sign.sign(privateKey); + + // Build the full certificate + const cert = buildCertificate(tbsCert, signature); + + // Convert to PEM + const certBase64 = cert.toString('base64'); + const certPem = '-----BEGIN CERTIFICATE-----\n' + + certBase64.match(/.{1,64}/g).join('\n') + + '\n-----END CERTIFICATE-----\n'; + + return { key: privateKey, cert: certPem }; +} + +// ASN.1 DER encoding helpers +function encodeLength(len) { + if (len < 128) return Buffer.from([len]); + if (len < 256) return Buffer.from([0x81, len]); + if (len < 65536) return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]); + throw new Error('Length too long'); +} + +function encodeSequence(contents) { + const len = encodeLength(contents.length); + return Buffer.concat([Buffer.from([0x30]), len, contents]); +} + +function encodeInteger(buf) { + // Add leading zero if high bit is set + if (buf[0] & 0x80) { + buf = Buffer.concat([Buffer.from([0x00]), buf]); + } + const len = encodeLength(buf.length); + return Buffer.concat([Buffer.from([0x02]), len, buf]); +} + +function encodeOID(oid) { + const parts = oid.split('.').map(Number); + const bytes = [parts[0] * 40 + parts[1]]; + for (let i = 2; i < parts.length; i++) { + let val = parts[i]; + if (val < 128) { + bytes.push(val); + } else { + const encoded = []; + while (val > 0) { + encoded.unshift((val & 0x7f) | (encoded.length ? 0x80 : 0)); + val >>= 7; + } + bytes.push(...encoded); + } + } + const buf = Buffer.from(bytes); + return Buffer.concat([Buffer.from([0x06]), encodeLength(buf.length), buf]); +} + +function encodeUTCTime(date) { + const str = date.toISOString().replace(/[-:T]/g, '').slice(2, 14) + 'Z'; + const buf = Buffer.from(str, 'ascii'); + return Buffer.concat([Buffer.from([0x17]), encodeLength(buf.length), buf]); +} + +function encodePrintableString(str) { + const buf = Buffer.from(str, 'ascii'); + return Buffer.concat([Buffer.from([0x13]), encodeLength(buf.length), buf]); +} + +function encodeSet(contents) { + const len = encodeLength(contents.length); + return Buffer.concat([Buffer.from([0x31]), len, contents]); +} + +function encodeBitString(buf) { + // Prepend with 0x00 to indicate no unused bits + const content = Buffer.concat([Buffer.from([0x00]), buf]); + return Buffer.concat([Buffer.from([0x03]), encodeLength(content.length), content]); +} + +function buildRDN(oid, value) { + const attrType = encodeOID(oid); + const attrValue = encodePrintableString(value); + const attrTypeAndValue = encodeSequence(Buffer.concat([attrType, attrValue])); + return encodeSet(attrTypeAndValue); +} + +function buildName() { + // CN=my.example.com,O=Mendhak,L=London,ST=London,C=GB + const cn = buildRDN('2.5.4.3', 'my.example.com'); // commonName + const o = buildRDN('2.5.4.10', 'Mendhak'); // organizationName + const l = buildRDN('2.5.4.7', 'London'); // localityName + const st = buildRDN('2.5.4.8', 'London'); // stateOrProvinceName + const c = buildRDN('2.5.4.6', 'GB'); // countryName + return encodeSequence(Buffer.concat([c, st, l, o, cn])); +} + +function buildValidity(notBefore, notAfter) { + return encodeSequence(Buffer.concat([ + encodeUTCTime(notBefore), + encodeUTCTime(notAfter) + ])); +} + +function buildAlgorithmIdentifier() { + // sha256WithRSAEncryption + const oid = encodeOID('1.2.840.113549.1.1.11'); + const params = Buffer.from([0x05, 0x00]); // NULL + return encodeSequence(Buffer.concat([oid, params])); +} + +function buildTBSCertificate(serialNumber, notBefore, notAfter, publicKeyDer) { + // Version (v3 = 2) + const version = Buffer.concat([ + Buffer.from([0xa0, 0x03, 0x02, 0x01, 0x02]) + ]); + + const serial = encodeInteger(serialNumber); + const signatureAlg = buildAlgorithmIdentifier(); + const issuer = buildName(); + const validity = buildValidity(notBefore, notAfter); + const subject = buildName(); + + // SubjectPublicKeyInfo is already in DER format + const subjectPublicKeyInfo = publicKeyDer; + + return encodeSequence(Buffer.concat([ + version, + serial, + signatureAlg, + issuer, + validity, + subject, + subjectPublicKeyInfo + ])); +} + +function buildCertificate(tbsCert, signature) { + const signatureAlg = buildAlgorithmIdentifier(); + const signatureValue = encodeBitString(signature); + + return encodeSequence(Buffer.concat([ + tbsCert, + signatureAlg, + signatureValue + ])); +} + const { PROMETHEUS_ENABLED = false, PROMETHEUS_METRICS_PATH = '/metrics', @@ -40,7 +243,15 @@ if(PROMETHEUS_ENABLED === 'true') { } if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ - app.use(morgan('combined')); + app.use(morgan('combined', { + skip: function (req, res) { + // Skip logging for paths matching LOG_IGNORE_PATH + if (process.env.LOG_IGNORE_PATH && new RegExp(process.env.LOG_IGNORE_PATH).test(req.path)) { + return true; + } + return false; + } + })); } app.use(function(req, res, next){ @@ -197,9 +408,10 @@ let httpOpts = { maxHeaderSize: maxHeaderSize } +const httpsCredentials = getHttpsCredentials(); let httpsOpts = { - key: require('fs').readFileSync(process.env.HTTPS_KEY_FILE || 'privkey.pem'), - cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem'), + key: httpsCredentials.key, + cert: httpsCredentials.cert, maxHeaderSize: maxHeaderSize }; diff --git a/package-lock.json b/package-lock.json index 794dcbb..8396e75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.21.2", + "express": "^4.22.0", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.1" @@ -30,9 +30,9 @@ } }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "license": "MIT", "dependencies": { "@types/connect": "*", @@ -49,20 +49,20 @@ } }, "node_modules/@types/express": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz", - "integrity": "sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "*" + "@types/serve-static": "^2" } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", - "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -72,30 +72,24 @@ } }, "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz", - "integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==", + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/qs": { - "version": "6.9.18", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", - "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "license": "MIT" }, "node_modules/@types/range-parser": { @@ -105,24 +99,22 @@ "license": "MIT" }, "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "license": "MIT", "dependencies": { - "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" + "@types/node": "*" } }, "node_modules/accepts": { @@ -170,23 +162,23 @@ "peer": true }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -280,18 +272,18 @@ } }, "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, "node_modules/debug": { @@ -406,39 +398,39 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -469,17 +461,17 @@ } }, "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -587,19 +579,23 @@ } }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/iconv-lite": { @@ -630,12 +626,12 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -658,23 +654,23 @@ "license": "MIT" }, "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==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "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==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -908,12 +904,12 @@ } }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -932,15 +928,15 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -987,9 +983,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -999,38 +995,29 @@ } }, "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1038,15 +1025,15 @@ "license": "MIT" }, "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.19.0" + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" @@ -1131,9 +1118,9 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -1187,9 +1174,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unpipe": { diff --git a/package.json b/package.json index 006bfc5..69547ec 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,12 @@ }, "dependencies": { "concat-stream": "^2.0.0", - "express": "^4.21.2", + "express": "^4.22.0", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.1" + }, + "overrides": { + "jws": "^3.2.3" } } diff --git a/tests.sh b/tests.sh index 1262fe7..6a18e78 100755 --- a/tests.sh +++ b/tests.sh @@ -416,7 +416,7 @@ docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 sleep 5 curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null -if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ +if [ $(docker logs http-echo-tests | wc -l) == 4 ] && \ [ $(docker logs http-echo-tests | grep tiramisu) ] then passed "LOG_WITHOUT_NEWLINE logged output in single line" From 15a58eb7b8dfa54b27f1c4eee3b583867bbe8072 Mon Sep 17 00:00:00 2001 From: Willy Guggenheim Date: Fri, 9 Jan 2026 11:51:38 -0800 Subject: [PATCH 093/123] reduce changes after finding a way to tell trivy that its's a test key only --- Dockerfile | 10 ++- README.md | 8 +- index.js | 218 +---------------------------------------------------- tests.sh | 12 +-- 4 files changed, 22 insertions(+), 226 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8ceaaa3..57ef1dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,10 +6,18 @@ COPY . /app RUN set -ex \ # Build JS-Application && npm install --production \ + # Generate SSL-certificate (for HTTPS) + && apk --no-cache add openssl \ + && openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout testpk.pem -out fullchain.pem \ + -subj "/C=GB/ST=London/L=London/O=Mendhak/CN=my.example.com" \ + -addext "subjectAltName=DNS:my.example.com,DNS:my.example.net,IP:192.168.50.108,IP:127.0.0.1" \ + && apk del openssl \ + && rm -rf /var/cache/apk/* \ # Delete unnecessary files && rm package* \ # Correct User's file access - && chown -R node:node /app + && chown -R node:node /app \ + && chmod +r /app/testpk.pem FROM node:22-alpine AS final LABEL \ diff --git a/README.md b/README.md index 4f0eebc..ab4d3cd 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ With docker compose, this would be: ## Use your own certificates -The certificates are at `/app/fullchain.pem` and `/app/privkey.pem`. +The certificates are at `/app/fullchain.pem` and `/app/testpk.pem`. You can use volume mounting to substitute the certificate and private key with your own. @@ -89,7 +89,7 @@ You can use volume mounting to substitute the certificate and private key with y - "8443:8443" volumes: - /etc/ssl/certs/ssl-cert-snakeoil.pem:/app/fullchain.pem - - /etc/ssl/private/ssl-cert-snakeoil.key:/app/privkey.pem + - /etc/ssl/private/ssl-cert-snakeoil.key:/app/testpk.pem You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to define the location of existing certificate and private key inside container. @@ -265,7 +265,7 @@ To get client certificate details in the response body, start the container with For example, invoke using curl, passing a certificate and key. ```bash -curl -k --cert cert.pem --key privkey.pem https://localhost:8443/ +curl -k --cert cert.pem --key testpk.pem https://localhost:8443/ ``` The response body will contain details about the client certificate passed in. @@ -273,7 +273,7 @@ The response body will contain details about the client certificate passed in. If you browse to https://localhost:8443/ in Firefox, you won't get prompted to supply a client certificate unless you have [an imported certificate by the same issuer as the server](https://superuser.com/questions/1043415/firefox-doesnt-ask-me-for-a-certificate-when-visiting-a-site-that-needs-one). If you need browser prompting to work, you'll need to follow the 'use your own certificates' section. Firefox needs the imported certificate to be in a PKCS12 format, so if you have a certificate and key already, you can combine them using ```bash -openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx +openssl pkcs12 -export -in cert.pem -inkey testpk.pem -out certpkcs12.pfx ``` ## Preserve the case of headers in response body diff --git a/index.js b/index.js index d43cba9..f408286 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,4 @@ const os = require('os'); -const fs = require('fs'); -const crypto = require('crypto'); const jwt = require('jsonwebtoken'); const http = require('http') const https = require('https') @@ -11,207 +9,6 @@ const { promisify } = require('util'); const promBundle = require("express-prom-bundle"); const zlib = require("zlib"); -// Get HTTPS credentials - either from files or generate self-signed in memory -function getHttpsCredentials() { - const keyFile = process.env.HTTPS_KEY_FILE; - const certFile = process.env.HTTPS_CERT_FILE; - - // If both files are specified and exist, use them - if (keyFile && certFile) { - try { - return { - key: fs.readFileSync(keyFile), - cert: fs.readFileSync(certFile) - }; - } catch (err) { - console.log(`Could not read cert files (${err.message}), generating self-signed certificate...`); - } - } - - // Try default file locations for backward compatibility - try { - return { - key: fs.readFileSync('privkey.pem'), - cert: fs.readFileSync('fullchain.pem') - }; - } catch (err) { - // Generate self-signed certificate in memory - console.log('Generating self-signed certificate in memory...'); - return generateSelfSignedCertificate(); - } -} - -// Generate a self-signed certificate entirely in memory -function generateSelfSignedCertificate() { - const { privateKey } = crypto.generateKeyPairSync('rsa', { - modulusLength: 2048, - publicKeyEncoding: { type: 'spki', format: 'pem' }, - privateKeyEncoding: { type: 'pkcs8', format: 'pem' } - }); - - const publicKey = crypto.createPublicKey(crypto.createPrivateKey(privateKey)); - - // Get the public key in DER format for the certificate - const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' }); - - // Create certificate structure - const serialNumber = crypto.randomBytes(8); - const now = new Date(); - const notBefore = now; - const notAfter = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000); - - // Build ASN.1 TBSCertificate - const tbsCert = buildTBSCertificate(serialNumber, notBefore, notAfter, publicKeyDer); - - // Sign the TBSCertificate - const sign = crypto.createSign('SHA256'); - sign.update(tbsCert); - const signature = sign.sign(privateKey); - - // Build the full certificate - const cert = buildCertificate(tbsCert, signature); - - // Convert to PEM - const certBase64 = cert.toString('base64'); - const certPem = '-----BEGIN CERTIFICATE-----\n' + - certBase64.match(/.{1,64}/g).join('\n') + - '\n-----END CERTIFICATE-----\n'; - - return { key: privateKey, cert: certPem }; -} - -// ASN.1 DER encoding helpers -function encodeLength(len) { - if (len < 128) return Buffer.from([len]); - if (len < 256) return Buffer.from([0x81, len]); - if (len < 65536) return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]); - throw new Error('Length too long'); -} - -function encodeSequence(contents) { - const len = encodeLength(contents.length); - return Buffer.concat([Buffer.from([0x30]), len, contents]); -} - -function encodeInteger(buf) { - // Add leading zero if high bit is set - if (buf[0] & 0x80) { - buf = Buffer.concat([Buffer.from([0x00]), buf]); - } - const len = encodeLength(buf.length); - return Buffer.concat([Buffer.from([0x02]), len, buf]); -} - -function encodeOID(oid) { - const parts = oid.split('.').map(Number); - const bytes = [parts[0] * 40 + parts[1]]; - for (let i = 2; i < parts.length; i++) { - let val = parts[i]; - if (val < 128) { - bytes.push(val); - } else { - const encoded = []; - while (val > 0) { - encoded.unshift((val & 0x7f) | (encoded.length ? 0x80 : 0)); - val >>= 7; - } - bytes.push(...encoded); - } - } - const buf = Buffer.from(bytes); - return Buffer.concat([Buffer.from([0x06]), encodeLength(buf.length), buf]); -} - -function encodeUTCTime(date) { - const str = date.toISOString().replace(/[-:T]/g, '').slice(2, 14) + 'Z'; - const buf = Buffer.from(str, 'ascii'); - return Buffer.concat([Buffer.from([0x17]), encodeLength(buf.length), buf]); -} - -function encodePrintableString(str) { - const buf = Buffer.from(str, 'ascii'); - return Buffer.concat([Buffer.from([0x13]), encodeLength(buf.length), buf]); -} - -function encodeSet(contents) { - const len = encodeLength(contents.length); - return Buffer.concat([Buffer.from([0x31]), len, contents]); -} - -function encodeBitString(buf) { - // Prepend with 0x00 to indicate no unused bits - const content = Buffer.concat([Buffer.from([0x00]), buf]); - return Buffer.concat([Buffer.from([0x03]), encodeLength(content.length), content]); -} - -function buildRDN(oid, value) { - const attrType = encodeOID(oid); - const attrValue = encodePrintableString(value); - const attrTypeAndValue = encodeSequence(Buffer.concat([attrType, attrValue])); - return encodeSet(attrTypeAndValue); -} - -function buildName() { - // CN=my.example.com,O=Mendhak,L=London,ST=London,C=GB - const cn = buildRDN('2.5.4.3', 'my.example.com'); // commonName - const o = buildRDN('2.5.4.10', 'Mendhak'); // organizationName - const l = buildRDN('2.5.4.7', 'London'); // localityName - const st = buildRDN('2.5.4.8', 'London'); // stateOrProvinceName - const c = buildRDN('2.5.4.6', 'GB'); // countryName - return encodeSequence(Buffer.concat([c, st, l, o, cn])); -} - -function buildValidity(notBefore, notAfter) { - return encodeSequence(Buffer.concat([ - encodeUTCTime(notBefore), - encodeUTCTime(notAfter) - ])); -} - -function buildAlgorithmIdentifier() { - // sha256WithRSAEncryption - const oid = encodeOID('1.2.840.113549.1.1.11'); - const params = Buffer.from([0x05, 0x00]); // NULL - return encodeSequence(Buffer.concat([oid, params])); -} - -function buildTBSCertificate(serialNumber, notBefore, notAfter, publicKeyDer) { - // Version (v3 = 2) - const version = Buffer.concat([ - Buffer.from([0xa0, 0x03, 0x02, 0x01, 0x02]) - ]); - - const serial = encodeInteger(serialNumber); - const signatureAlg = buildAlgorithmIdentifier(); - const issuer = buildName(); - const validity = buildValidity(notBefore, notAfter); - const subject = buildName(); - - // SubjectPublicKeyInfo is already in DER format - const subjectPublicKeyInfo = publicKeyDer; - - return encodeSequence(Buffer.concat([ - version, - serial, - signatureAlg, - issuer, - validity, - subject, - subjectPublicKeyInfo - ])); -} - -function buildCertificate(tbsCert, signature) { - const signatureAlg = buildAlgorithmIdentifier(); - const signatureValue = encodeBitString(signature); - - return encodeSequence(Buffer.concat([ - tbsCert, - signatureAlg, - signatureValue - ])); -} - const { PROMETHEUS_ENABLED = false, PROMETHEUS_METRICS_PATH = '/metrics', @@ -243,15 +40,7 @@ if(PROMETHEUS_ENABLED === 'true') { } if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ - app.use(morgan('combined', { - skip: function (req, res) { - // Skip logging for paths matching LOG_IGNORE_PATH - if (process.env.LOG_IGNORE_PATH && new RegExp(process.env.LOG_IGNORE_PATH).test(req.path)) { - return true; - } - return false; - } - })); + app.use(morgan('combined')); } app.use(function(req, res, next){ @@ -408,10 +197,9 @@ let httpOpts = { maxHeaderSize: maxHeaderSize } -const httpsCredentials = getHttpsCredentials(); let httpsOpts = { - key: httpsCredentials.key, - cert: httpsCredentials.cert, + key: require('fs').readFileSync(process.env.HTTPS_KEY_FILE || 'testpk.pem'), + cert: require('fs').readFileSync(process.env.HTTPS_CERT_FILE || 'fullchain.pem'), maxHeaderSize: maxHeaderSize }; diff --git a/tests.sh b/tests.sh index 6a18e78..f78844a 100755 --- a/tests.sh +++ b/tests.sh @@ -416,7 +416,7 @@ docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 sleep 5 curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null -if [ $(docker logs http-echo-tests | wc -l) == 4 ] && \ +if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ [ $(docker logs http-echo-tests | grep tiramisu) ] then passed "LOG_WITHOUT_NEWLINE logged output in single line" @@ -471,13 +471,13 @@ sleep 5 message " Check that mTLS server responds with client certificate details" # Generate a new self signed cert locally -openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout privkey.pem -out fullchain.pem \ +openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout testpk.pem -out fullchain.pem \ -subj "/CN=client.example.net" \ -addext "subjectAltName=DNS:client.example.net" docker run -d --rm -e MTLS_ENABLE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing sleep 5 -COMMON_NAME="$(curl -sk --cert fullchain.pem --key privkey.pem https://localhost:8443/ | jq -r '.clientCertificate.subject.CN')" -SAN="$(curl -sk --cert fullchain.pem --key privkey.pem https://localhost:8443/ | jq -r '.clientCertificate.subjectaltname')" +COMMON_NAME="$(curl -sk --cert fullchain.pem --key testpk.pem https://localhost:8443/ | jq -r '.clientCertificate.subject.CN')" +SAN="$(curl -sk --cert fullchain.pem --key testpk.pem https://localhost:8443/ | jq -r '.clientCertificate.subjectaltname')" if [ "$COMMON_NAME" == "client.example.net" ] && [ "$SAN" == "DNS:client.example.net" ] then passed "Client certificate details are present in the output" @@ -497,7 +497,7 @@ else fi message " Check that HTTP server does not have any client certificate property" -CLIENT_CERT=$(curl -sk --cert cert.pem --key privkey.pem http://localhost:8080/ | jq 'has("clientCertificate")') +CLIENT_CERT=$(curl -sk --cert cert.pem --key testpk.pem http://localhost:8080/ | jq 'has("clientCertificate")') if [ "$CLIENT_CERT" == "false" ] then passed "Client certificate details are not present in regular HTTP server" @@ -513,7 +513,7 @@ sleep 5 message " Check that SSL certificate and private key are loaded from custom location" cert_common_name="server.example.net" https_cert_file="$(pwd)/server_fullchain.pem" -https_key_file="$(pwd)/server_privkey.pem" +https_key_file="$(pwd)/server_testpk.pem" # Generate a new self signed cert locally openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout "${https_key_file}" -out "${https_cert_file}" \ -subj "/CN=${cert_common_name}" \ From ae037290f21e516c670d08c2dd2a6c58ed78508d Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 9 Jan 2026 21:54:32 +0000 Subject: [PATCH 094/123] Add a changelog for v40 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c9eb98..87192f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Version `40` - 2026-01-09 +* Renamed privkey.pem to testpk.pem so Trivy doesn't flag a false positive by [willyguggenheim](https://github.com/mendhak/docker-http-https-echo/pull/89) +* Updated dependencies in package.json + ## Version `39` - 2025-11-21 * Removed `/usr/local/lib/node_modules` from image to reduce CVE footprint From 792fc1ad1105456bcd0c761b05499e68a07cba53 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 9 Jan 2026 21:56:17 +0000 Subject: [PATCH 095/123] Actually it's version 39 due --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87192f0..f494b79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,6 @@ -## Version `40` - 2026-01-09 +## Version `39` - 2026-01-09 * Renamed privkey.pem to testpk.pem so Trivy doesn't flag a false positive by [willyguggenheim](https://github.com/mendhak/docker-http-https-echo/pull/89) * Updated dependencies in package.json - -## Version `39` - 2025-11-21 * Removed `/usr/local/lib/node_modules` from image to reduce CVE footprint ## Version `38` - 2025-10-24 From e609311f3925ca2e5a82864253e9ad2506797a37 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 9 Jan 2026 21:56:44 +0000 Subject: [PATCH 096/123] Update to version 39 --- README.md | 36 ++++++++++++++++++------------------ docker-compose.yml | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index ab4d3cd..e716926 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:38` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:38` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:39` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:39` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:38 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:39 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:38 + image: mendhak/http-https-echo:39 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/testpk.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:38 + image: mendhak/http-https-echo:39 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:38 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:39 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 ## Do not log specific path @@ -120,12 +120,12 @@ Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would li This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. # Ignore a single path - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 # Ignore multiple paths - docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 # Ignore all paths - docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 - docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 + docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 + docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 @@ -152,7 +152,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 ``` ## Send an empty response @@ -160,7 +160,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 ``` ## Custom status code @@ -241,7 +241,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -281,7 +281,7 @@ openssl pkcs12 -export -in cert.pem -inkey testpk.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:38 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 ``` ## Override the response body with a file @@ -290,7 +290,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:38 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:39 ``` ## Set a maximum header size @@ -298,7 +298,7 @@ docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_R You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header size in bytes. The default is 1MB. ```bash -docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:38 +docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 ``` diff --git a/docker-compose.yml b/docker-compose.yml index 971e7e2..699ce4f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:38 + image: mendhak/http-https-echo:39 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 634cac3a55ea1f3bb3463bbef233bd50b3f138a4 Mon Sep 17 00:00:00 2001 From: Willy Guggenheim Date: Fri, 6 Feb 2026 05:09:45 +0000 Subject: [PATCH 097/123] Add apk upgrade to fix OpenSSL CVEs in cached base image The node:22-alpine base image may serve stale OS packages when built with Docker layer cache. Adding apk upgrade ensures libcrypto3/libssl3 are updated to 3.5.5-r0, resolving CVE-2025-15467, CVE-2025-69419, and CVE-2025-69421. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 57ef1dc..2e97b7b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ LABEL \ org.opencontainers.image.source="https://github.com/mendhak/docker-http-https-echo" \ org.opencontainers.image.licenses="MIT" WORKDIR /app -RUN rm -rf /usr/local/lib/node_modules +RUN apk upgrade --no-cache && rm -rf /usr/local/lib/node_modules COPY --from=build /app /app ENV HTTP_PORT=8080 HTTPS_PORT=8443 EXPOSE $HTTP_PORT $HTTPS_PORT From 55892c5fe04a6a8d1792356dd13102819609d2bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 12:44:26 +0000 Subject: [PATCH 098/123] Bump qs from 6.14.1 to 6.14.2 Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2) --- updated-dependencies: - dependency-name: qs dependency-version: 6.14.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8396e75..e36edc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -904,9 +904,9 @@ } }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" From 335fb23a0f555b79c6ddf81cfdb6ff6afca6e4ae Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 19 Mar 2026 23:12:17 +0000 Subject: [PATCH 099/123] Add cookie parser to echo the value of cookies in the response. Also works for signed cookies. To sign a cookie, generate a value using SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); function sign(val, secret){ return val + '.' + crypto .createHmac('sha256', secret) .update(val) .digest('base64') .replace(/=+$/, ''); }; console.log(sign('my-value','mysecretkey123'));") Then send it in the header like so curl -s http://localhost:8080/ -H "Cookie: mysigned=s:${SIGNED_COOKIE}" Issue #93 --- index.js | 4 ++++ package-lock.json | 20 ++++++++++++++++++ package.json | 1 + tests.sh | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/index.js b/index.js index f408286..5876532 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ const http = require('http') const https = require('https') const morgan = require('morgan'); const express = require('express') +const cookieParser = require('cookie-parser'); const concat = require('concat-stream'); const { promisify } = require('util'); const promBundle = require("express-prom-bundle"); @@ -39,6 +40,8 @@ if(PROMETHEUS_ENABLED === 'true') { app.use(metricsMiddleware); } +app.use(cookieParser(process.env.COOKIE_SECRET || 'examplekey')); + if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ app.use(morgan('combined')); } @@ -76,6 +79,7 @@ app.all('*', (req, res) => { ips: req.ips, protocol: req.protocol, query: req.query, + signedCookies: req.signedCookies, subdomains: req.subdomains, xhr: req.xhr, os: { diff --git a/package-lock.json b/package-lock.json index e36edc8..36b0fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", + "cookie-parser": "^1.4.6", "express": "^4.22.0", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", @@ -280,6 +281,25 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, "node_modules/cookie-signature": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", diff --git a/package.json b/package.json index 69547ec..2fd41c2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", + "cookie-parser": "^1.4.6", "express": "^4.22.0", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", diff --git a/tests.sh b/tests.sh index f78844a..73cca7f 100755 --- a/tests.sh +++ b/tests.sh @@ -653,6 +653,60 @@ message " Stop containers " docker stop http-echo-tests sleep 5 +message " Start container with signed cookies support " +# Set cookie secret for signing/verifying cookies +docker run -d --rm -e COOKIE_SECRET=mysecretkey123 \ + --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +sleep 5 + +SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); + +function sign(val, secret){ + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/=+$/, ''); +}; + +console.log(sign('my-value','mysecretkey123'));") + + +RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: mysigned=s:${SIGNED_COOKIE}") +if [ $(echo $RESPONSE | jq -r '.signedCookies.mysigned') == 'my-value' ] +then + passed "Signed cookie test passed." +else + failed "Signed cookie test failed." + echo $RESPONSE | jq + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + + +message " Check that regular cookies are returned in response " +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +sleep 5 + + +RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux") +if [ $(echo $RESPONSE | jq -r '.cookies.foo') == 'bar' ] && \ + [ $(echo $RESPONSE | jq -r '.cookies.baz') == 'qux' ] +then + passed "Cookies returned in response test passed." +else + failed "Cookies returned in response test failed." + echo $RESPONSE | jq + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + popd rm -rf testarea message "DONE" From 67da5eb9bd277aff2fcec87e4a61a36a2a3e7d73 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 07:25:17 +0000 Subject: [PATCH 100/123] Update the sarif actions --- .github/workflows/build.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a89eebf..5037958 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,10 @@ jobs: # The type of runner that the job will run on runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -76,7 +80,7 @@ jobs: - name: Scan the image id: scan - uses: anchore/scan-action@v3 + uses: anchore/scan-action@v7 with: image: "mendhak/http-https-echo:testing" output-format: sarif @@ -84,6 +88,6 @@ jobs: fail-build: false - name: upload Anchore scan SARIF report - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: ${{ steps.scan.outputs.sarif }} From ba1c32982dc541455e7ba86289d36499c4d9decf Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 07:51:41 +0000 Subject: [PATCH 101/123] How to send a signed cookie --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index e716926..2e720a1 100644 --- a/README.md +++ b/README.md @@ -301,6 +301,47 @@ You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header s docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 ``` +## Cookies and Signed Cookies + +Make a request with a `Cookie` header and the response will include the cookies: + +```bash +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +``` + +Then make a request with a cookie header: + +```bash +curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux" +``` + +To enable signed cookie support, set the `COOKIE_SECRET` environment variable. Signed cookies appear in the `signedCookies` section of the response: + +```bash +docker run -d --rm -e COOKIE_SECRET=mysecretkey123 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +``` + +Now you need to generate a signed cookie, and send it in the header. Here's a convenience node snippet: + +```bash + +SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); + +function sign(val, secret){ + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/=+$/, ''); +}; + +console.log(sign('my-value','mysecretkey123'));") + +curl -s http://localhost:8080/ -H "Cookie: mysigned=s:$SIGNED_COOKIE" | jq '.signedCookies' +``` + +Notice the `s:` prefix in the cookie value, that is important. + ## Prometheus Metrics From 4f118c005be9847c59608d0c9c6264fa1dc1fde9 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 07:53:12 +0000 Subject: [PATCH 102/123] Changelog for v40 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f494b79..d86685f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `40` - 2026-03-20 +* Echo back cookies and signed cookies + ## Version `39` - 2026-01-09 * Renamed privkey.pem to testpk.pem so Trivy doesn't flag a false positive by [willyguggenheim](https://github.com/mendhak/docker-http-https-echo/pull/89) * Updated dependencies in package.json From 35299e2cfbcfb0451140dffd4b3a6497608bd710 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 08:05:35 +0000 Subject: [PATCH 103/123] version 40 --- README.md | 40 ++++++++++++++++++++-------------------- docker-compose.yml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 2e720a1..c5e355d 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:39` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:39` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:40` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:40` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -44,7 +44,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 Or run with Docker Compose @@ -61,13 +61,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:39 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:40 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:39 + image: mendhak/http-https-echo:40 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -83,7 +83,7 @@ The certificates are at `/app/fullchain.pem` and `/app/testpk.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:39 + image: mendhak/http-https-echo:40 ports: - "8080:8080" - "8443:8443" @@ -98,7 +98,7 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:39 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:40 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -111,7 +111,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 ## Do not log specific path @@ -120,12 +120,12 @@ Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would li This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. # Ignore a single path - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 # Ignore multiple paths - docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 # Ignore all paths - docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 - docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 + docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 + docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 @@ -152,7 +152,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 ``` ## Send an empty response @@ -160,7 +160,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 ``` ## Custom status code @@ -241,7 +241,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -281,7 +281,7 @@ openssl pkcs12 -export -in cert.pem -inkey testpk.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:39 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 ``` ## Override the response body with a file @@ -290,7 +290,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:39 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:40 ``` ## Set a maximum header size @@ -298,7 +298,7 @@ docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_R You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header size in bytes. The default is 1MB. ```bash -docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 ``` ## Cookies and Signed Cookies @@ -306,7 +306,7 @@ docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak Make a request with a `Cookie` header and the response will include the cookies: ```bash -docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 ``` Then make a request with a cookie header: @@ -318,7 +318,7 @@ curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux" To enable signed cookie support, set the `COOKIE_SECRET` environment variable. Signed cookies appear in the `signedCookies` section of the response: ```bash -docker run -d --rm -e COOKIE_SECRET=mysecretkey123 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +docker run -d --rm -e COOKIE_SECRET=mysecretkey123 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 ``` Now you need to generate a signed cookie, and send it in the header. Here's a convenience node snippet: diff --git a/docker-compose.yml b/docker-compose.yml index 699ce4f..2e4fb1d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:39 + image: mendhak/http-https-echo:40 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 From 064b2d214c7f4f7e29a083921b4c6e5dec159c94 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 08:10:19 +0000 Subject: [PATCH 104/123] TOC update --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c5e355d..dfcbbd5 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,12 @@ This image is executed as non root by default and is fully compliant with Kubern - [Add a delay before response](#add-a-delay-before-response) - [Only return body in the response](#only-return-body-in-the-response) - [Include environment variables in the response](#include-environment-variables-in-the-response) -- [Configuring CORS policy](#setting-corscross-origin-resource-sharing-headers-in-the-response) +- [Setting CORS(Cross-Origin Resource Sharing) headers in the response](#setting-corscross-origin-resource-sharing-headers-in-the-response) - [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response) - [Preserve the case of headers in response body](#preserve-the-case-of-headers-in-response-body) - [Override the response body with a file](#override-the-response-body-with-a-file) +- [Set a maximum header size](#set-a-maximum-header-size) +- [Cookies and Signed Cookies](#cookies-and-signed-cookies) - [Prometheus Metrics](#prometheus-metrics) - [Screenshots](#screenshots) - [Building](#building) From e8bb97ca5ccae6d5b556c65a2c375ef03efaa8de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 11:20:16 +0000 Subject: [PATCH 105/123] Bump path-to-regexp from 0.1.12 to 0.1.13 Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 0.1.12 to 0.1.13. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/v.0.1.13/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.12...v.0.1.13) --- updated-dependencies: - dependency-name: path-to-regexp dependency-version: 0.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 36b0fd9..6971bc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -891,9 +891,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/prom-client": { From def8198fb099ce18c15d5b23c97c79209c34265a Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 21:27:27 +0100 Subject: [PATCH 106/123] Improve tests speed --- tests.sh | 142 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 51 deletions(-) diff --git a/tests.sh b/tests.sh index 73cca7f..9a597ab 100755 --- a/tests.sh +++ b/tests.sh @@ -21,6 +21,27 @@ function passed { echo ${GREEN}✓$1${RESTORE} } +wait_for_ready() { + local check_path="${1:-/}" + for i in {1..30}; do + if curl -sf "http://localhost:8080${check_path}" >/dev/null 2>&1; then + return 0 + fi + sleep 0.5 + done + echo "Container failed to start"; exit 1 +} + +wait_for_removed() { + for i in {1..30}; do + if ! docker ps -q --filter "name=http-echo-tests" | grep -q .; then + return 0 + fi + sleep 0.5 + done + echo "Container failed to stop"; exit 1 +} + if ! [ -x "$(command -v jq)" ]; then message "JQ not installed. Installing..." sudo apt -y install jq @@ -44,11 +65,12 @@ mkdir -p testarea pushd testarea message " Cleaning up from previous test run " -docker ps -aq --filter "name=http-echo-tests" | grep -q . && docker stop http-echo-tests && docker rm -f http-echo-tests +docker rm -f http-echo-tests 2>/dev/null || true +wait_for_removed message " Start container normally " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 10 +wait_for_ready message " Make http(s) request, and test the path, method, header and status code. " @@ -178,11 +200,11 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with max header size " docker run -d --rm -e MAX_HEADER_SIZE=1000 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 10 +wait_for_ready message " Make request with a header within limit." LARGE_HEADER_VALUE=$(head -c 600 /dev/null -if [ $(docker logs http-echo-tests | wc -l) == 2 ] && \ +# There should be 3 lines, the "listening on...", the /ping ready test, and the /ping POST test. +if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ ! [ $(docker logs http-echo-tests | grep banana) ] then passed "LOG_IGNORE_PATH ignored the /ping path" @@ -319,14 +344,16 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with LOG_IGNORE_PATH (regex path)" docker run -d --rm -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready "/health" + curl -s -k -X POST -d "banana" https://localhost:8443/metrics > /dev/null -if [ $(docker logs http-echo-tests | wc -l) == 2 ] && \ +# There should be 3 lines, the "listening on...", the /health ready test, and the /metrics POST test. +if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ ! [ $(docker logs http-echo-tests | grep banana) ] then passed "LOG_IGNORE_PATH ignored the /metrics path" @@ -351,14 +378,16 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with LOG_IGNORE_PATH (ignore all paths) " docker run -d --rm -e LOG_IGNORE_PATH=".*" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready "/hello" + curl -s -k -X POST -d "banana" https://localhost:8443/ > /dev/null -if [ $(docker logs http-echo-tests | wc -l) == 2 ] && \ +# There should be 3 lines, the "listening on", the "/hello" ready test, and the POST banana test. +if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ ! [ $(docker logs http-echo-tests | grep banana) ] then passed "LOG_IGNORE_PATH ignored all paths" @@ -370,12 +399,13 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with DISABLE_REQUEST_LOGS " docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready "/healthy" + curl -s -k -X GET https://localhost:8443/strawberry > /dev/null if [ $(docker logs http-echo-tests | grep -c "GET /strawberry HTTP/1.1") -eq 0 ] then @@ -388,13 +418,14 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with CORS_CONFIG" docker run -d --rm \ -e CORS_ALLOW_ORIGIN="http://example.com" -e CORS_ALLOW_HEADERS="x-custom-test-header" \ --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + # Check if the expected CORS headers are present in the response if curl -s -i http://localhost:8080/ 2>&1 | grep -q -E \ "Access-Control-Allow-Headers: x-custom-test-header" && @@ -409,14 +440,16 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with LOG_WITHOUT_NEWLINE " docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null -if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ +# There will be 4 lines, the Listening on, the / ready test and response, the POST test and response +if [ $(docker logs http-echo-tests | wc -l) == 5 ] && \ [ $(docker logs http-echo-tests | grep tiramisu) ] then passed "LOG_WITHOUT_NEWLINE logged output in single line" @@ -429,7 +462,7 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that container is running as a NON ROOT USER by default" docker run -d --name http-echo-tests --rm mendhak/http-https-echo:testing @@ -446,13 +479,14 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that container is running as user different that the user defined in image" IMAGE_USER="$(docker image inspect mendhak/http-https-echo:testing -f '{{ .Config.User }}')" CONTAINER_USER="$((IMAGE_USER + 1000000))" docker run -d --name http-echo-tests --rm -u "${CONTAINER_USER}" -p 8080:8080 mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + curl -s http://localhost:8080 > /dev/null WHOAMI="$(docker exec http-echo-tests id -u)" @@ -467,7 +501,7 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that mTLS server responds with client certificate details" # Generate a new self signed cert locally @@ -475,7 +509,8 @@ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout testpk.pem -subj "/CN=client.example.net" \ -addext "subjectAltName=DNS:client.example.net" docker run -d --rm -e MTLS_ENABLE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + COMMON_NAME="$(curl -sk --cert fullchain.pem --key testpk.pem https://localhost:8443/ | jq -r '.clientCertificate.subject.CN')" SAN="$(curl -sk --cert fullchain.pem --key testpk.pem https://localhost:8443/ | jq -r '.clientCertificate.subjectaltname')" if [ "$COMMON_NAME" == "client.example.net" ] && [ "$SAN" == "DNS:client.example.net" ] @@ -508,7 +543,7 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that SSL certificate and private key are loaded from custom location" cert_common_name="server.example.net" @@ -542,11 +577,12 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that environment variables returned in response if enabled" docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + RESPONSE_BODY="$(curl -sk https://localhost:8443/ | jq -r '.env.ECHO_INCLUDE_ENV_VARS')" if [ "$RESPONSE_BODY" == "1" ] @@ -559,11 +595,12 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that environment variables are not present in response by default" docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + RESPONSE_BODY_ENV_CHECK="$(curl -sk https://localhost:8443/ | jq 'has("env")')" if [ "$RESPONSE_BODY_ENV_CHECK" == "false" ] @@ -576,11 +613,12 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with PROMETHEUS disabled " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null # grep for http_request_duration_seconds_count ensure it is not present at /metric path @@ -597,11 +635,12 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with PROMETHEUS enabled " docker run -d -e PROMETHEUS_ENABLED=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null METRICS_CHECK="$(curl -sk http://localhost:8080/metrics | grep http_request_duration_seconds_count )" @@ -617,12 +656,12 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with PRESERVE_HEADER_CASE enabled " docker run -d -e PRESERVE_HEADER_CASE=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +wait_for_ready -sleep 5 HEADER_CASE_CHECK=$(curl -s -H "prEseRVe-CaSE: A1b2C3" -H 'x-a-b: 999' -H 'X-a-B: 13' localhost:8080 | jq -r '.headers."prEseRVe-CaSE"') if [[ "$HEADER_CASE_CHECK" == "A1b2C3" ]] then @@ -634,12 +673,13 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with a custom response body from a file " echo "

Hello World

" > test.html docker run -d --rm -v ${PWD}/test.html:/app/test.html --name http-echo-tests -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready + RESPONSE_BODY=$(curl -s http://localhost:8080) if [[ "$RESPONSE_BODY" == "

Hello World

" ]] then @@ -651,13 +691,13 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Start container with signed cookies support " # Set cookie secret for signing/verifying cookies docker run -d --rm -e COOKIE_SECRET=mysecretkey123 \ --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); @@ -684,12 +724,12 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed message " Check that regular cookies are returned in response " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 +wait_for_ready RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux") @@ -705,7 +745,7 @@ fi message " Stop containers " docker stop http-echo-tests -sleep 5 +wait_for_removed popd rm -rf testarea From 69c03d9818f2b1daec5b5ed370b0ade8534a163e Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 21:30:09 +0100 Subject: [PATCH 107/123] Another sleep replacement --- tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests.sh b/tests.sh index 9a597ab..225fccc 100755 --- a/tests.sh +++ b/tests.sh @@ -562,8 +562,8 @@ docker run -d --rm \ -e HTTPS_CERT_FILE="${container_https_cert_file}" \ -v "${https_key_file}:${container_https_key_file}:ro,z" \ -e HTTPS_KEY_FILE="${container_https_key_file}" \ - --name http-echo-tests -p 8443:8443 -t mendhak/http-https-echo:testing -sleep 5 + --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +wait_for_ready REQUEST_WITH_STATUS_CODE="$(curl -s --cacert "$(pwd)/server_fullchain.pem" -o /dev/null -w "%{http_code}" \ --resolve "${cert_common_name}:8443:127.0.0.1" "https://${cert_common_name}:8443/hello-world")" From 48da00d3dbca309e241a05c3645961563a3e8cab Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 21:30:27 +0100 Subject: [PATCH 108/123] Group dependabot stuff together --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7ee231c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 10 + groups: + production-dependencies: + patterns: + - "*" From 00d9ed7bca96885b96d857d7f26639ca8f46c512 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 21:44:56 +0100 Subject: [PATCH 109/123] Trap and clean up --- tests.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests.sh b/tests.sh index 225fccc..f1be0e7 100755 --- a/tests.sh +++ b/tests.sh @@ -34,7 +34,7 @@ wait_for_ready() { wait_for_removed() { for i in {1..30}; do - if ! docker ps -q --filter "name=http-echo-tests" | grep -q .; then + if ! docker ps -aq --filter "name=http-echo-tests" | grep -q .; then return 0 fi sleep 0.5 @@ -42,6 +42,16 @@ wait_for_removed() { echo "Container failed to stop"; exit 1 } +cleanup() { + echo "Cleaning up..." + docker stop http-echo-tests 2>/dev/null || true + docker rm http-echo-tests 2>/dev/null || true + popd 2>/dev/null || true + rm -rf testarea +} + +trap cleanup EXIT + if ! [ -x "$(command -v jq)" ]; then message "JQ not installed. Installing..." sudo apt -y install jq @@ -747,6 +757,4 @@ message " Stop containers " docker stop http-echo-tests wait_for_removed -popd -rm -rf testarea message "DONE" From 538a4984dff114c11af5c9d3c7ca1bbbcab8fb85 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 22:17:51 +0100 Subject: [PATCH 110/123] Quote variables --- tests.sh | 106 ++++++++++++++++++++++++------------------------------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/tests.sh b/tests.sh index f1be0e7..9be476c 100755 --- a/tests.sh +++ b/tests.sh @@ -85,36 +85,33 @@ wait_for_ready message " Make http(s) request, and test the path, method, header and status code. " REQUEST=$(curl -s -k -X PUT -H "Arbitrary:Header" -d aaa=bbb 'https://localhost:8443/hello-world?ccc=ddd&myquery=98765') -if [ $(echo $REQUEST | jq -r '.path') == '/hello-world' ] && \ - [ $(echo $REQUEST | jq -r '.method') == 'PUT' ] && \ - [ $(echo $REQUEST | jq -r '.query.myquery') == '98765' ] && \ - [ $(echo $REQUEST | jq -r '.headers.arbitrary') == 'Header' ] -then +if [ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ] && \ + [ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ] && \ + [ "$(echo "$REQUEST" | jq -r '.query.myquery')" == '98765' ] && \ + [ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]; then passed "HTTPS request passed." else failed "HTTPS request failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi REQUEST_WITH_STATUS_CODE=$(curl -s -k -o /dev/null -w "%{http_code}" -H "x-set-response-status-code: 404" https://localhost:8443/hello-world) REQUEST_WITH_STATUS_CODE_V=$(curl -v -k -o /dev/null -w "%{http_code}" -H "x-set-response-status-code: 404" https://localhost:8443/hello-world) -if [ $(echo $REQUEST_WITH_STATUS_CODE == '404') ] -then +if [ "$REQUEST_WITH_STATUS_CODE" = "404" ]; then passed "HTTPS status code header passed." else failed "HTTPS status code header failed." - echo $REQUEST_WITH_STATUS_CODE_V + echo "$REQUEST_WITH_STATUS_CODE_V" exit 1 fi REQUEST_WITH_STATUS_CODE=$(curl -s -k -o /dev/null -w "%{http_code}" https://localhost:8443/status/test?x-set-response-status-code=419) REQUEST_WITH_STATUS_CODE_V=$(curl -v -k -o /dev/null -w "%{http_code}" https://localhost:8443/hello-world?x-set-response-status-code=419) -if [ $(echo $REQUEST_WITH_STATUS_CODE == '419') ] -then +if [ "$REQUEST_WITH_STATUS_CODE" = "419" ]; then passed "HTTPS status code querystring passed." else failed "HTTPS status code querystring failed." - echo $REQUEST_WITH_STATUS_CODE_V + echo "$REQUEST_WITH_STATUS_CODE_V" exit 1 fi @@ -122,7 +119,7 @@ REQUEST_WITH_CONTENT_TYPE_HEADER=$(curl -o /dev/null -k -Ss -w "%{content_type}" if [[ "$REQUEST_WITH_CONTENT_TYPE_HEADER" == *"aaaa/bbbb"* ]]; then passed "Request with custom response type header, passed" else - echo $REQUEST_WITH_CONTENT_TYPE_HEADER + echo "$REQUEST_WITH_CONTENT_TYPE_HEADER" failed "Request with custom response type header, failed." exit 1 fi @@ -131,7 +128,7 @@ REQUEST_WITH_CONTENT_TYPE_PARAMETER=$(curl -o /dev/null -k -Ss -w "%{content_typ if [[ "$REQUEST_WITH_CONTENT_TYPE_PARAMETER" == *"jellyfish/cabbage"* ]]; then passed "Request with custom response type parameter, passed" else - echo $REQUEST_WITH_CONTENT_TYPE_PARAMETER + echo "$REQUEST_WITH_CONTENT_TYPE_PARAMETER" failed "Request with custom response type parameter, failed." exit 1 fi @@ -142,7 +139,7 @@ if [[ $(echo "$REQUEST_WITH_SLEEP_MS>5" | bc -l) == 1 ]]; then passed "Request header with response delay passed" else failed "Request header with response delay failed" - echo $REQUEST_WITH_SLEEP_MS + echo "$REQUEST_WITH_SLEEP_MS" exit 1 fi @@ -151,7 +148,7 @@ if [[ $(echo "$REQUEST_WITH_SLEEP_MS>4" | bc -l) == 1 ]]; then passed "Request query with response delay passed" else failed "Request query with response delay failed" - echo $REQUEST_WITH_SLEEP_MS + echo "$REQUEST_WITH_SLEEP_MS" exit 1 fi @@ -160,51 +157,48 @@ if [[ $(echo "$REQUEST_WITH_INVALID_SLEEP_MS<2" | bc -l) == 1 ]]; then passed "Request with invalid response delay passed" else failed "Request with invalid response delay failed" - echo $REQUEST_WITH_INVALID_SLEEP_MS + echo "$REQUEST_WITH_INVALID_SLEEP_MS" exit 1 fi REQUEST=$(curl -s -X PUT -H "Arbitrary:Header" -d aaa=bbb http://localhost:8080/hello-world) -if [ $(echo $REQUEST | jq -r '.path') == '/hello-world' ] && \ - [ $(echo $REQUEST | jq -r '.method') == 'PUT' ] && \ - [ $(echo $REQUEST | jq -r '.headers.arbitrary') == 'Header' ] -then +if [ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ] && \ + [ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ] && \ + [ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]; then passed "HTTP request with arbitrary header passed." else failed "HTTP request with arbitrary header failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi message " Make JSON request, and test that json is in the output. " REQUEST=$(curl -s -X POST -H "Content-Type: application/json" -d '{"a":"b"}' http://localhost:8080/) -if [ $(echo $REQUEST | jq -r '.json.a') == 'b' ] -then +if [ "$(echo "$REQUEST" | jq -r '.json.a')" == 'b' ]; then passed "JSON test passed." else failed "JSON test failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi message " Make JSON request with gzip Content-Encoding, and test that json is in the output. " REQUEST=$(echo -n '{"a":"b"}' | gzip | curl -s -X POST -H "Content-Encoding: gzip" -H "Content-Type: application/json" --data-binary @- http://localhost:8080/) -if [ $(echo $REQUEST | jq -r '.json.a') == 'b' ] -then +if [ "$(echo "$REQUEST" | jq -r '.json.a')" == 'b' ]; then passed "JSON test passed." else failed "JSON test failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi REQUEST=$(curl -s -X POST -H "Content-Type: application/json" -d 'not-json' http://localhost:8080) -if [ $(echo $REQUEST | jq -r '.json') == 'null' ]; then +if [ "$(echo "$REQUEST" | jq -r '.json')" == 'null' ]; then passed "JSON with Invalid Body test passed." else failed "JSON with Invalid Body test failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi @@ -220,11 +214,11 @@ message " Make request with a header within limit." LARGE_HEADER_VALUE=$(head -c 600 &1) -if echo $REQUEST | grep -q "HTTP/1.1 431 Request Header Fields Too Large"; then +if echo "$REQUEST" | grep -q "HTTP/1.1 431 Request Header Fields Too Large"; then passed "Large header test resulted in HTTP 431." else failed "Large header test failed." - echo $REQUEST + echo "$REQUEST" exit 1 fi @@ -250,26 +244,24 @@ wait_for_ready message " Make http(s) request, and test the path, method and header. " REQUEST=$(curl -s -k -X PUT -H "Arbitrary:Header" -d aaa=bbb https://localhost:8443/hello-world) -if [ $(echo $REQUEST | jq -r '.path') == '/hello-world' ] && \ - [ $(echo $REQUEST | jq -r '.method') == 'PUT' ] && \ - [ $(echo $REQUEST | jq -r '.headers.arbitrary') == 'Header' ] -then +if [ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ] && \ + [ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ] && \ + [ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]; then passed "HTTPS request passed." else failed "HTTPS request failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi REQUEST=$(curl -s -X PUT -H "Arbitrary:Header" -d aaa=bbb http://localhost:8080/hello-world) -if [ $(echo $REQUEST | jq -r '.path') == '/hello-world' ] && \ - [ $(echo $REQUEST | jq -r '.method') == 'PUT' ] && \ - [ $(echo $REQUEST | jq -r '.headers.arbitrary') == 'Header' ] -then +if [ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ] && \ + [ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ] && \ + [ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]; then passed "HTTP request passed." else failed "HTTP request failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi @@ -300,12 +292,11 @@ message " Start container with response body only " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing wait_for_ready RESPONSE=$(curl -s -k -X POST -d 'cauliflower' http://localhost:8080/a/b/c?response_body_only=true) -if [[ ${RESPONSE} == "cauliflower" ]] -then +if [[ "$RESPONSE" == "cauliflower" ]]; then passed "Response body only received." else failed "Expected response body only." - echo $RESPONSE + echo "$RESPONSE" exit 1 fi @@ -319,14 +310,13 @@ docker run -d --rm -e JWT_HEADER=Authentication --name http-echo-tests -p 8080:8 wait_for_ready REQUEST=$(curl -s -k -H "Authentication: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" https://localhost:8443/ ) -if [ $(echo $REQUEST | jq -r '.jwt.header.typ') == 'JWT' ] && \ - [ $(echo $REQUEST | jq -r '.jwt.header.alg') == 'HS256' ] && \ - [ $(echo $REQUEST | jq -r '.jwt.payload.sub') == '1234567890' ] -then +if [ "$(echo "$REQUEST" | jq -r '.jwt.header.typ')" == 'JWT' ] && \ + [ "$(echo "$REQUEST" | jq -r '.jwt.header.alg')" == 'HS256' ] && \ + [ "$(echo "$REQUEST" | jq -r '.jwt.payload.sub')" == '1234567890' ]; then passed "JWT request passed." else failed "JWT request failed." - echo $REQUEST | jq + echo "$REQUEST" | jq exit 1 fi @@ -723,12 +713,11 @@ console.log(sign('my-value','mysecretkey123'));") RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: mysigned=s:${SIGNED_COOKIE}") -if [ $(echo $RESPONSE | jq -r '.signedCookies.mysigned') == 'my-value' ] -then +if [ "$(echo "$RESPONSE" | jq -r '.signedCookies.mysigned')" == 'my-value' ]; then passed "Signed cookie test passed." else failed "Signed cookie test failed." - echo $RESPONSE | jq + echo "$RESPONSE" | jq exit 1 fi @@ -743,13 +732,12 @@ wait_for_ready RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux") -if [ $(echo $RESPONSE | jq -r '.cookies.foo') == 'bar' ] && \ - [ $(echo $RESPONSE | jq -r '.cookies.baz') == 'qux' ] -then +if [ "$(echo "$RESPONSE" | jq -r '.cookies.foo')" == 'bar' ] && \ + [ "$(echo "$RESPONSE" | jq -r '.cookies.baz')" == 'qux' ]; then passed "Cookies returned in response test passed." else failed "Cookies returned in response test failed." - echo $RESPONSE | jq + echo "$RESPONSE" | jq exit 1 fi From 2f9e5e6c2764a46789fa2f9414522e90bbccd054 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 22:23:28 +0100 Subject: [PATCH 111/123] A little more consistency with square brackets --- tests.sh | 104 +++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/tests.sh b/tests.sh index 9be476c..a7df672 100755 --- a/tests.sh +++ b/tests.sh @@ -5,7 +5,7 @@ set -euo pipefail function message { echo "" echo "---------------------------------------------------------------" - echo $1 + echo "$1" echo "---------------------------------------------------------------" } @@ -14,11 +14,11 @@ RED=$(echo -en '\033[01;31m') GREEN=$(echo -en '\033[01;32m') function failed { - echo ${RED}✗$1${RESTORE} + echo "${RED}✗${1}${RESTORE}" } function passed { - echo ${GREEN}✓$1${RESTORE} + echo "${GREEN}✓${1}${RESTORE}" } wait_for_ready() { @@ -52,16 +52,16 @@ cleanup() { trap cleanup EXIT -if ! [ -x "$(command -v jq)" ]; then +if ! command -v jq >/dev/null 2>&1; then message "JQ not installed. Installing..." sudo apt -y install jq fi message " Check if we're in Github Actions or local run " -if [ -n "${GITHUB_ACTIONS:-}" ]; then +if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo " Github Actions. Image should already be built." docker images - if [ -z "$(docker images -q mendhak/http-https-echo:testing 2> /dev/null)" ]; then + if [[ -z "$(docker images -q mendhak/http-https-echo:testing 2> /dev/null)" ]]; then echo "Docker image mendhak/http-https-echo:testing not found. Exiting." exit 1 fi @@ -85,10 +85,10 @@ wait_for_ready message " Make http(s) request, and test the path, method, header and status code. " REQUEST=$(curl -s -k -X PUT -H "Arbitrary:Header" -d aaa=bbb 'https://localhost:8443/hello-world?ccc=ddd&myquery=98765') -if [ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ] && \ - [ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ] && \ - [ "$(echo "$REQUEST" | jq -r '.query.myquery')" == '98765' ] && \ - [ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]; then +if [[ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ]] && \ + [[ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ]] && \ + [[ "$(echo "$REQUEST" | jq -r '.query.myquery')" == '98765' ]] && \ + [[ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]]; then passed "HTTPS request passed." else failed "HTTPS request failed." @@ -97,7 +97,7 @@ else fi REQUEST_WITH_STATUS_CODE=$(curl -s -k -o /dev/null -w "%{http_code}" -H "x-set-response-status-code: 404" https://localhost:8443/hello-world) REQUEST_WITH_STATUS_CODE_V=$(curl -v -k -o /dev/null -w "%{http_code}" -H "x-set-response-status-code: 404" https://localhost:8443/hello-world) -if [ "$REQUEST_WITH_STATUS_CODE" = "404" ]; then +if [[ "$REQUEST_WITH_STATUS_CODE" == "404" ]]; then passed "HTTPS status code header passed." else failed "HTTPS status code header failed." @@ -107,7 +107,7 @@ fi REQUEST_WITH_STATUS_CODE=$(curl -s -k -o /dev/null -w "%{http_code}" https://localhost:8443/status/test?x-set-response-status-code=419) REQUEST_WITH_STATUS_CODE_V=$(curl -v -k -o /dev/null -w "%{http_code}" https://localhost:8443/hello-world?x-set-response-status-code=419) -if [ "$REQUEST_WITH_STATUS_CODE" = "419" ]; then +if [[ "$REQUEST_WITH_STATUS_CODE" == "419" ]]; then passed "HTTPS status code querystring passed." else failed "HTTPS status code querystring failed." @@ -162,9 +162,9 @@ else fi REQUEST=$(curl -s -X PUT -H "Arbitrary:Header" -d aaa=bbb http://localhost:8080/hello-world) -if [ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ] && \ - [ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ] && \ - [ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]; then +if [[ "$(echo "$REQUEST" | jq -r '.path')" == '/hello-world' ]] && \ + [[ "$(echo "$REQUEST" | jq -r '.method')" == 'PUT' ]] && \ + [[ "$(echo "$REQUEST" | jq -r '.headers.arbitrary')" == 'Header' ]]; then passed "HTTP request with arbitrary header passed." else failed "HTTP request with arbitrary header failed." @@ -174,7 +174,7 @@ fi message " Make JSON request, and test that json is in the output. " REQUEST=$(curl -s -X POST -H "Content-Type: application/json" -d '{"a":"b"}' http://localhost:8080/) -if [ "$(echo "$REQUEST" | jq -r '.json.a')" == 'b' ]; then +if [[ "$(echo "$REQUEST" | jq -r '.json.a')" == 'b' ]]; then passed "JSON test passed." else failed "JSON test failed." @@ -185,7 +185,7 @@ fi message " Make JSON request with gzip Content-Encoding, and test that json is in the output. " REQUEST=$(echo -n '{"a":"b"}' | gzip | curl -s -X POST -H "Content-Encoding: gzip" -H "Content-Type: application/json" --data-binary @- http://localhost:8080/) -if [ "$(echo "$REQUEST" | jq -r '.json.a')" == 'b' ]; then +if [[ "$(echo "$REQUEST" | jq -r '.json.a')" == 'b' ]]; then passed "JSON test passed." else failed "JSON test failed." @@ -194,7 +194,7 @@ else fi REQUEST=$(curl -s -X POST -H "Content-Type: application/json" -d 'not-json' http://localhost:8080) -if [ "$(echo "$REQUEST" | jq -r '.json')" == 'null' ]; then +if [[ "$(echo "$REQUEST" | jq -r '.json')" == 'null' ]]; then passed "JSON with Invalid Body test passed." else failed "JSON with Invalid Body test failed." @@ -214,7 +214,7 @@ message " Make request with a header within limit." LARGE_HEADER_VALUE=$(head -c 600 /dev/null # There should be 3 lines, the "listening on...", the /ping ready test, and the /ping POST test. -if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ - ! [ $(docker logs http-echo-tests | grep banana) ] +if [[ "$(docker logs http-echo-tests | wc -l)" == 3 ]] && \ + ! docker logs http-echo-tests | grep -q banana then passed "LOG_IGNORE_PATH ignored the /ping path" else @@ -353,8 +353,8 @@ wait_for_ready "/health" curl -s -k -X POST -d "banana" https://localhost:8443/metrics > /dev/null # There should be 3 lines, the "listening on...", the /health ready test, and the /metrics POST test. -if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ - ! [ $(docker logs http-echo-tests | grep banana) ] +if [[ "$(docker logs http-echo-tests | wc -l)" == 3 ]] && \ + ! docker logs http-echo-tests | grep -q banana then passed "LOG_IGNORE_PATH ignored the /metrics path" else @@ -366,7 +366,7 @@ fi # Test a positive case where the path is not ignored curl -s -k -X POST -d "strawberry" https://localhost:8443/veryvisible > /dev/null -if [[ $(docker logs http-echo-tests | grep strawberry) ]] +if docker logs http-echo-tests | grep -q strawberry then passed "LOG_IGNORE_PATH didn't ignore the /veryvisible path" else @@ -387,8 +387,8 @@ wait_for_ready "/hello" curl -s -k -X POST -d "banana" https://localhost:8443/ > /dev/null # There should be 3 lines, the "listening on", the "/hello" ready test, and the POST banana test. -if [ $(docker logs http-echo-tests | wc -l) == 3 ] && \ - ! [ $(docker logs http-echo-tests | grep banana) ] +if [[ "$(docker logs http-echo-tests | wc -l)" == 3 ]] && \ + ! docker logs http-echo-tests | grep -q banana then passed "LOG_IGNORE_PATH ignored all paths" else @@ -407,7 +407,7 @@ docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8 wait_for_ready "/healthy" curl -s -k -X GET https://localhost:8443/strawberry > /dev/null -if [ $(docker logs http-echo-tests | grep -c "GET /strawberry HTTP/1.1") -eq 0 ] +if [[ "$(docker logs http-echo-tests | grep -c "GET /strawberry HTTP/1.1")" -eq 0 ]] then passed "DISABLE_REQUEST_LOGS disabled Express HTTP logging" else @@ -449,8 +449,8 @@ wait_for_ready curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null # There will be 4 lines, the Listening on, the / ready test and response, the POST test and response -if [ $(docker logs http-echo-tests | wc -l) == 5 ] && \ - [ $(docker logs http-echo-tests | grep tiramisu) ] +if [[ "$(docker logs http-echo-tests | wc -l)" == 5 ]] && \ + docker logs http-echo-tests | grep -q tiramisu then passed "LOG_WITHOUT_NEWLINE logged output in single line" else @@ -469,7 +469,7 @@ docker run -d --name http-echo-tests --rm mendhak/http-https-echo:testing WHOAMI=$(docker exec http-echo-tests whoami) -if [ "$WHOAMI" == "node" ] +if [[ "$WHOAMI" == "node" ]] then passed "Running as non root user" else @@ -491,7 +491,7 @@ curl -s http://localhost:8080 > /dev/null WHOAMI="$(docker exec http-echo-tests id -u)" -if [ "$WHOAMI" == "$CONTAINER_USER" ] +if [[ "$WHOAMI" == "$CONTAINER_USER" ]] then passed "Running as $CONTAINER_USER user" else @@ -513,7 +513,7 @@ wait_for_ready COMMON_NAME="$(curl -sk --cert fullchain.pem --key testpk.pem https://localhost:8443/ | jq -r '.clientCertificate.subject.CN')" SAN="$(curl -sk --cert fullchain.pem --key testpk.pem https://localhost:8443/ | jq -r '.clientCertificate.subjectaltname')" -if [ "$COMMON_NAME" == "client.example.net" ] && [ "$SAN" == "DNS:client.example.net" ] +if [[ "$COMMON_NAME" == "client.example.net" && "$SAN" == "DNS:client.example.net" ]] then passed "Client certificate details are present in the output" else @@ -523,7 +523,7 @@ fi message " Check if certificate is not passed, then client certificate details are empty" CLIENT_CERT="$(curl -sk https://localhost:8443/ | jq -r '.clientCertificate')" -if [ "$CLIENT_CERT" == "{}" ] +if [[ "$CLIENT_CERT" == "{}" ]] then passed "Client certificate details are not present in the response" else @@ -533,7 +533,7 @@ fi message " Check that HTTP server does not have any client certificate property" CLIENT_CERT=$(curl -sk --cert cert.pem --key testpk.pem http://localhost:8080/ | jq 'has("clientCertificate")') -if [ "$CLIENT_CERT" == "false" ] +if [[ "$CLIENT_CERT" == "false" ]] then passed "Client certificate details are not present in regular HTTP server" else @@ -567,7 +567,7 @@ wait_for_ready REQUEST_WITH_STATUS_CODE="$(curl -s --cacert "$(pwd)/server_fullchain.pem" -o /dev/null -w "%{http_code}" \ --resolve "${cert_common_name}:8443:127.0.0.1" "https://${cert_common_name}:8443/hello-world")" -if [ "${REQUEST_WITH_STATUS_CODE}" = 200 ] +if [[ "${REQUEST_WITH_STATUS_CODE}" == 200 ]] then passed "Server certificate and private key are loaded from configured custom location" else @@ -585,7 +585,7 @@ wait_for_ready RESPONSE_BODY="$(curl -sk https://localhost:8443/ | jq -r '.env.ECHO_INCLUDE_ENV_VARS')" -if [ "$RESPONSE_BODY" == "1" ] +if [[ "$RESPONSE_BODY" == "1" ]] then passed "Environment variables present in the output" else @@ -603,7 +603,7 @@ wait_for_ready RESPONSE_BODY_ENV_CHECK="$(curl -sk https://localhost:8443/ | jq 'has("env")')" -if [ "$RESPONSE_BODY_ENV_CHECK" == "false" ] +if [[ "$RESPONSE_BODY_ENV_CHECK" == "false" ]] then passed "Environment variables not present in the output by default" else @@ -677,7 +677,7 @@ wait_for_removed message " Start container with a custom response body from a file " echo "

Hello World

" > test.html -docker run -d --rm -v ${PWD}/test.html:/app/test.html --name http-echo-tests -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:testing +docker run -d --rm -v "${PWD}/test.html:/app/test.html" --name http-echo-tests -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:testing wait_for_ready RESPONSE_BODY=$(curl -s http://localhost:8080) @@ -713,7 +713,7 @@ console.log(sign('my-value','mysecretkey123'));") RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: mysigned=s:${SIGNED_COOKIE}") -if [ "$(echo "$RESPONSE" | jq -r '.signedCookies.mysigned')" == 'my-value' ]; then +if [[ "$(echo "$RESPONSE" | jq -r '.signedCookies.mysigned')" == 'my-value' ]]; then passed "Signed cookie test passed." else failed "Signed cookie test failed." @@ -732,8 +732,8 @@ wait_for_ready RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux") -if [ "$(echo "$RESPONSE" | jq -r '.cookies.foo')" == 'bar' ] && \ - [ "$(echo "$RESPONSE" | jq -r '.cookies.baz')" == 'qux' ]; then +if [[ "$(echo "$RESPONSE" | jq -r '.cookies.foo')" == 'bar' ]] && \ + [[ "$(echo "$RESPONSE" | jq -r '.cookies.baz')" == 'qux' ]]; then passed "Cookies returned in response test passed." else failed "Cookies returned in response test failed." From a84c25827134cf746b10bb522c5713849eb700c4 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 22:25:30 +0100 Subject: [PATCH 112/123] Slightly fewer iterations --- tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests.sh b/tests.sh index a7df672..91e7aad 100755 --- a/tests.sh +++ b/tests.sh @@ -23,7 +23,7 @@ function passed { wait_for_ready() { local check_path="${1:-/}" - for i in {1..30}; do + for i in {1..20}; do if curl -sf "http://localhost:8080${check_path}" >/dev/null 2>&1; then return 0 fi @@ -33,7 +33,7 @@ wait_for_ready() { } wait_for_removed() { - for i in {1..30}; do + for i in {1..20}; do if ! docker ps -aq --filter "name=http-echo-tests" | grep -q .; then return 0 fi From 77ce22aa9a1aaebb212d3faabd251dcfb3eeb50c Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 22:33:55 +0100 Subject: [PATCH 113/123] Consolidate stop requests --- tests.sh | 77 ++++++++++++++++++++------------------------------------ 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/tests.sh b/tests.sh index 91e7aad..03b203a 100755 --- a/tests.sh +++ b/tests.sh @@ -32,7 +32,8 @@ wait_for_ready() { echo "Container failed to start"; exit 1 } -wait_for_removed() { +stop_and_remove() { + docker stop http-echo-tests 2>/dev/null || true for i in {1..20}; do if ! docker ps -aq --filter "name=http-echo-tests" | grep -q .; then return 0 @@ -76,7 +77,7 @@ pushd testarea message " Cleaning up from previous test run " docker rm -f http-echo-tests 2>/dev/null || true -wait_for_removed +stop_and_remove message " Start container normally " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -203,8 +204,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with max header size " docker run -d --rm -e MAX_HEADER_SIZE=1000 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -235,8 +235,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with different internal ports " docker run -d --rm -e HTTP_PORT=8888 -e HTTPS_PORT=9999 --name http-echo-tests -p 8080:8888 -p 8443:9999 -t mendhak/http-https-echo:testing @@ -267,8 +266,7 @@ fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with empty responses " docker run -d --rm -e ECHO_BACK_TO_CLIENT=false --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -285,8 +283,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with response body only " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -302,8 +299,7 @@ fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with JWT_HEADER " docker run -d --rm -e JWT_HEADER=Authentication --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -321,8 +317,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with LOG_IGNORE_PATH (normal path)" @@ -343,8 +338,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with LOG_IGNORE_PATH (regex path)" docker run -d --rm -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -377,8 +371,7 @@ fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with LOG_IGNORE_PATH (ignore all paths) " docker run -d --rm -e LOG_IGNORE_PATH=".*" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -398,8 +391,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with DISABLE_REQUEST_LOGS " @@ -417,8 +409,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with CORS_CONFIG" docker run -d --rm \ @@ -439,8 +430,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with LOG_WITHOUT_NEWLINE " docker run -d --rm -e LOG_WITHOUT_NEWLINE=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -461,8 +451,7 @@ fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that container is running as a NON ROOT USER by default" docker run -d --name http-echo-tests --rm mendhak/http-https-echo:testing @@ -478,8 +467,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that container is running as user different that the user defined in image" IMAGE_USER="$(docker image inspect mendhak/http-https-echo:testing -f '{{ .Config.User }}')" @@ -500,8 +488,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that mTLS server responds with client certificate details" # Generate a new self signed cert locally @@ -542,8 +529,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that SSL certificate and private key are loaded from custom location" cert_common_name="server.example.net" @@ -576,8 +562,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that environment variables returned in response if enabled" docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -594,8 +579,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that environment variables are not present in response by default" docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -612,8 +596,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with PROMETHEUS disabled " docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -634,8 +617,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with PROMETHEUS enabled " docker run -d -e PROMETHEUS_ENABLED=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -655,8 +637,7 @@ fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with PRESERVE_HEADER_CASE enabled " docker run -d -e PRESERVE_HEADER_CASE=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing @@ -672,8 +653,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with a custom response body from a file " echo "

Hello World

" > test.html @@ -690,8 +670,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Start container with signed cookies support " # Set cookie secret for signing/verifying cookies @@ -722,8 +701,7 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message " Check that regular cookies are returned in response " @@ -742,7 +720,6 @@ else fi message " Stop containers " -docker stop http-echo-tests -wait_for_removed +stop_and_remove message "DONE" From 10af7eee6182613028b76f54a8513b3d242acae2 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 3 Apr 2026 22:51:22 +0100 Subject: [PATCH 114/123] Plaintext test clarification --- tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests.sh b/tests.sh index 03b203a..330d68e 100755 --- a/tests.sh +++ b/tests.sh @@ -518,8 +518,8 @@ else exit 1 fi -message " Check that HTTP server does not have any client certificate property" -CLIENT_CERT=$(curl -sk --cert cert.pem --key testpk.pem http://localhost:8080/ | jq 'has("clientCertificate")') +message " Check that plaintext HTTP port does not have any client certificate property" +CLIENT_CERT=$(curl -s http://localhost:8080/ | jq 'has("clientCertificate")') if [[ "$CLIENT_CERT" == "false" ]] then passed "Client certificate details are not present in regular HTTP server" From 2eda5793f29bba0054bb372469d436a4ad96e96f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 11:15:27 +0000 Subject: [PATCH 115/123] Bump express from 4.22.1 to 5.2.1 in the production-dependencies group Bumps the production-dependencies group with 1 update: [express](https://github.com/expressjs/express). Updates `express` from 4.22.1 to 5.2.1 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/v4.22.1...v5.2.1) --- updated-dependencies: - dependency-name: express dependency-version: 5.2.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 518 ++++++++++++++++++++++++++++------------------ package.json | 2 +- 2 files changed, 323 insertions(+), 197 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6971bc3..9774eab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "concat-stream": "^2.0.0", "cookie-parser": "^1.4.6", - "express": "^4.22.0", + "express": "^5.2.1", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.1" @@ -119,24 +119,18 @@ } }, "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -163,29 +157,52 @@ "peer": true }, "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, + "node_modules/body-parser/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "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", @@ -252,15 +269,16 @@ } }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -301,10 +319,13 @@ "license": "MIT" }, "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } }, "node_modules/debug": { "version": "2.6.9", @@ -324,16 +345,6 @@ "node": ">= 0.8" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -418,45 +429,42 @@ } }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" }, "funding": { "type": "opencollective", @@ -480,24 +488,73 @@ "prom-client": ">=15.0.0" } }, + "node_modules/express/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -508,12 +565,12 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/function-bind": { @@ -619,15 +676,19 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/inherits": { @@ -645,6 +706,12 @@ "node": ">= 0.10" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", @@ -746,63 +813,49 @@ } }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" + "node": ">=18" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/morgan": { @@ -840,9 +893,9 @@ "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -881,6 +934,15 @@ "node": ">= 0.8" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -891,10 +953,14 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", - "license": "MIT" + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/prom-client": { "version": "15.1.3", @@ -924,9 +990,9 @@ } }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -948,18 +1014,18 @@ } }, "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", + "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/readable-stream": { @@ -976,6 +1042,45 @@ "node": ">= 6" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/router/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1015,27 +1120,46 @@ } }, "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/send/node_modules/ms": { @@ -1045,18 +1169,22 @@ "license": "MIT" }, "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { @@ -1175,13 +1303,14 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { "node": ">= 0.6" @@ -1223,15 +1352,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1240,6 +1360,12 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" } } } diff --git a/package.json b/package.json index 2fd41c2..927f2ff 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "dependencies": { "concat-stream": "^2.0.0", "cookie-parser": "^1.4.6", - "express": "^4.22.0", + "express": "^5.2.1", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", "morgan": "^1.10.1" From 1baeaae8f2b29eb8b2619334ec68b56d147a9f9b Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 4 Apr 2026 12:40:47 +0100 Subject: [PATCH 116/123] New catch all syntax for Express 5 --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 5876532..a7b92c6 100644 --- a/index.js +++ b/index.js @@ -58,8 +58,8 @@ app.use(function(req, res, next){ next(); })); }); -//Handle all paths -app.all('*', (req, res) => { +//Handle all paths. This /{*splat} is new Express 5 path syntax. https://expressjs.com/en/guide/migrating-5.html#path-syntax +app.all('/{*splat}', (req, res) => { if(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH){ // Path is relative to current directory From 89c541a844120c09f08c0e42b6337031e6afef16 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sat, 4 Apr 2026 13:07:50 +0100 Subject: [PATCH 117/123] Avoid pipe reading docker logs for tests --- tests.sh | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/tests.sh b/tests.sh index 330d68e..c6fa41d 100755 --- a/tests.sh +++ b/tests.sh @@ -327,13 +327,15 @@ wait_for_ready "/ping" curl -s -k -X POST -d "banana" https://localhost:8443/ping > /dev/null # There should be 3 lines, the "listening on...", the /ping ready test, and the /ping POST test. -if [[ "$(docker logs http-echo-tests | wc -l)" == 3 ]] && \ - ! docker logs http-echo-tests | grep -q banana +LOG_OUTPUT="$(docker logs http-echo-tests 2>&1)" +LINE_COUNT=$(( $(wc -l <<< "$LOG_OUTPUT") )) +if [[ "$LINE_COUNT" == 3 ]] && \ + ! grep -q banana <<< "$LOG_OUTPUT" then passed "LOG_IGNORE_PATH ignored the /ping path" else failed "LOG_IGNORE_PATH failed" - docker logs http-echo-tests + echo "$LOG_OUTPUT" exit 1 fi @@ -347,25 +349,28 @@ wait_for_ready "/health" curl -s -k -X POST -d "banana" https://localhost:8443/metrics > /dev/null # There should be 3 lines, the "listening on...", the /health ready test, and the /metrics POST test. -if [[ "$(docker logs http-echo-tests | wc -l)" == 3 ]] && \ - ! docker logs http-echo-tests | grep -q banana +LOG_OUTPUT="$(docker logs http-echo-tests 2>&1)" +LINE_COUNT=$(( $(wc -l <<< "$LOG_OUTPUT") )) +if [[ "$LINE_COUNT" == 3 ]] && \ + ! grep -q banana <<< "$LOG_OUTPUT" then passed "LOG_IGNORE_PATH ignored the /metrics path" else failed "LOG_IGNORE_PATH failed" - docker logs http-echo-tests + echo "$LOG_OUTPUT" exit 1 fi # Test a positive case where the path is not ignored curl -s -k -X POST -d "strawberry" https://localhost:8443/veryvisible > /dev/null -if docker logs http-echo-tests | grep -q strawberry +LOG_OUTPUT="$(docker logs http-echo-tests 2>&1)" +if grep -q strawberry <<< "$LOG_OUTPUT" then passed "LOG_IGNORE_PATH didn't ignore the /veryvisible path" else failed "LOG_IGNORE_PATH failed, it should not ignore the /veryvisible path" - docker logs http-echo-tests + echo "$LOG_OUTPUT" exit 1 fi @@ -380,13 +385,15 @@ wait_for_ready "/hello" curl -s -k -X POST -d "banana" https://localhost:8443/ > /dev/null # There should be 3 lines, the "listening on", the "/hello" ready test, and the POST banana test. -if [[ "$(docker logs http-echo-tests | wc -l)" == 3 ]] && \ - ! docker logs http-echo-tests | grep -q banana +LOG_OUTPUT="$(docker logs http-echo-tests 2>&1)" +LINE_COUNT=$(( $(wc -l <<< "$LOG_OUTPUT") )) +if [[ "$LINE_COUNT" == 3 ]] && \ + ! grep -q banana <<< "$LOG_OUTPUT" then passed "LOG_IGNORE_PATH ignored all paths" else failed "LOG_IGNORE_PATH failed" - docker logs http-echo-tests + echo "$LOG_OUTPUT" exit 1 fi @@ -399,12 +406,13 @@ docker run -d --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8 wait_for_ready "/healthy" curl -s -k -X GET https://localhost:8443/strawberry > /dev/null -if [[ "$(docker logs http-echo-tests | grep -c "GET /strawberry HTTP/1.1")" -eq 0 ]] +LOG_OUTPUT="$(docker logs http-echo-tests 2>&1)" +if [[ "$(grep -c "GET /strawberry HTTP/1.1" <<< "$LOG_OUTPUT")" -eq 0 ]] then passed "DISABLE_REQUEST_LOGS disabled Express HTTP logging" else failed "DISABLE_REQUEST_LOGS failed" - docker logs http-echo-tests + echo "$LOG_OUTPUT" exit 1 fi @@ -439,13 +447,15 @@ wait_for_ready curl -s -k -X POST -d "tiramisu" https://localhost:8443/ > /dev/null # There will be 4 lines, the Listening on, the / ready test and response, the POST test and response -if [[ "$(docker logs http-echo-tests | wc -l)" == 5 ]] && \ - docker logs http-echo-tests | grep -q tiramisu +LOG_OUTPUT="$(docker logs http-echo-tests 2>&1)" +LINE_COUNT=$(( $(wc -l <<< "$LOG_OUTPUT") )) +if [[ "$LINE_COUNT" == 5 ]] && \ + grep -q tiramisu <<< "$LOG_OUTPUT" then passed "LOG_WITHOUT_NEWLINE logged output in single line" else failed "LOG_WITHOUT_NEWLINE failed" - docker logs http-echo-tests + echo "$LOG_OUTPUT" exit 1 fi From fd37f48211ff9a3db5446f94d538a05015e3ed56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:49:59 +0000 Subject: [PATCH 118/123] Bump morgan from 1.10.1 to 1.11.0 in the production-dependencies group Bumps the production-dependencies group with 1 update: [morgan](https://github.com/expressjs/morgan). Updates `morgan` from 1.10.1 to 1.11.0 - [Release notes](https://github.com/expressjs/morgan/releases) - [Changelog](https://github.com/expressjs/morgan/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/morgan/compare/1.10.1...1.11.0) --- updated-dependencies: - dependency-name: morgan dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 24 ++++++++---------------- package.json | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9774eab..2018e62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "express": "^5.2.1", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", - "morgan": "^1.10.1" + "morgan": "^1.11.0" }, "engines": { "node": ">=16.0.0" @@ -859,31 +859,23 @@ } }, "node_modules/morgan": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", - "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.11.0.tgz", + "integrity": "sha512-zSkVu3t18r39pw4ixfBKvfZi3y2UOqr7d4WYwcj3m8nXpEQK4rPO6GLzs/CExoRgmX3y9EjmmcXqv6jq0SK46g==", "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", "depd": "~2.0.0", - "on-finished": "~2.3.0", + "on-finished": "~2.4.1", "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" - } - }, - "node_modules/morgan/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" }, - "engines": { - "node": ">= 0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ms": { diff --git a/package.json b/package.json index 927f2ff..2fb0627 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "express": "^5.2.1", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", - "morgan": "^1.10.1" + "morgan": "^1.11.0" }, "overrides": { "jws": "^3.2.3" From e0e50ec631b0cf26d5fbe6cbf6e5dd43a6fc59fe Mon Sep 17 00:00:00 2001 From: Jack Myers Date: Sun, 14 Jun 2026 16:53:30 +0800 Subject: [PATCH 119/123] feat: add an ENV var to configure trusting additional proxy IPs/subnets --- README.md | 8 ++++++++ index.js | 11 +++++++++-- tests.sh | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dfcbbd5..a62686a 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This image is executed as non root by default and is fully compliant with Kubern - [Basic Usage](#basic-usage) - [Choose your ports](#choose-your-ports) - [Use your own certificates](#use-your-own-certificates) +- [Trust additional proxy IPs](#trust-additional-proxy-ips) - [Decode JWT header](#decode-jwt-header) - [Disable ExpressJS log lines](#disable-expressjs-log-lines) - [Do not log specific path](#do-not-log-specific-path) @@ -96,6 +97,13 @@ You can use volume mounting to substitute the certificate and private key with y You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to define the location of existing certificate and private key inside container. +## Trust additional proxy IPs + +By default, Express is configured to trust forwarded proxy headers from loopback, link-local, and private IP ranges. To also trust additional proxy IPs or subnets, set `ADDITIONAL_TRUSTED_PROXIES` to a single value or a comma-separated list. + + docker run -e ADDITIONAL_TRUSTED_PROXIES="2001:db8::/32,203.0.113.10" -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 + + ## Decode JWT header If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. diff --git a/index.js b/index.js index a7b92c6..006d49e 100644 --- a/index.js +++ b/index.js @@ -17,11 +17,18 @@ const { PROMETHEUS_WITH_METHOD = 'true', PROMETHEUS_WITH_STATUS = 'true', PROMETHEUS_METRIC_TYPE = 'summary', - MAX_HEADER_SIZE = 1048576 + MAX_HEADER_SIZE = 1048576, + ADDITIONAL_TRUSTED_PROXIES } = process.env const maxHeaderSize = parseInt(MAX_HEADER_SIZE, 10) || 1048576; +const trustProxy = [ + 'loopback', + 'linklocal', + 'uniquelocal', + ...(ADDITIONAL_TRUSTED_PROXIES || '').split(',').map(proxy => proxy.trim()).filter(Boolean) +]; const sleep = promisify(setTimeout); const metricsMiddleware = promBundle({ @@ -34,7 +41,7 @@ const metricsMiddleware = promBundle({ const app = express() app.set('json spaces', 2); -app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); +app.set('trust proxy', trustProxy); if(PROMETHEUS_ENABLED === 'true') { app.use(metricsMiddleware); diff --git a/tests.sh b/tests.sh index c6fa41d..0bee232 100755 --- a/tests.sh +++ b/tests.sh @@ -237,6 +237,22 @@ fi message " Stop containers " stop_and_remove +message " Start container with additional trusted proxies " +docker run -d --rm -e ADDITIONAL_TRUSTED_PROXIES="2001:db8::/32,198.51.100.0/24" --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +wait_for_ready + +REQUEST=$(curl -s -H "X-Forwarded-For: 203.0.113.10, 198.51.100.1, 2001:db8::1" http://localhost:8080/) +if [[ "$(echo "$REQUEST" | jq -r '.ip')" == '203.0.113.10' ]]; then + passed "Additional trusted proxies passed." +else + failed "Additional trusted proxies failed." + echo "$REQUEST" | jq + exit 1 +fi + +message " Stop containers " +stop_and_remove + message " Start container with different internal ports " docker run -d --rm -e HTTP_PORT=8888 -e HTTPS_PORT=9999 --name http-echo-tests -p 8080:8888 -p 8443:9999 -t mendhak/http-https-echo:testing wait_for_ready From 48e1cdb26aa46a5a93a403e0982c65fb42e523d7 Mon Sep 17 00:00:00 2001 From: Jack Myers Date: Sun, 14 Jun 2026 16:58:23 +0800 Subject: [PATCH 120/123] fix(test): ignore `curl` exit code when sending a large header --- tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests.sh b/tests.sh index c6fa41d..e34b2ba 100755 --- a/tests.sh +++ b/tests.sh @@ -225,7 +225,7 @@ fi message " Make request with a header exceeding limit." LARGE_HEADER_VALUE=$(head -c 5000 &1) +REQUEST=$(curl -v -k -H "Large-Header: $LARGE_HEADER_VALUE" https://localhost:8443/ 2>&1 || true) if echo "$REQUEST" | grep -q "HTTP/1.1 431 Request Header Fields Too Large"; then passed "Large header test resulted in HTTP 431." else From 8528b224797df6763dc11e6559a2750d311ad700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 09:44:29 +0000 Subject: [PATCH 121/123] Bump qs from 6.15.0 to 6.15.2 Bumps [qs](https://github.com/ljharb/qs) from 6.15.0 to 6.15.2. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.15.0...v6.15.2) --- updated-dependencies: - dependency-name: qs dependency-version: 6.15.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2018e62..d6b2533 100644 --- a/package-lock.json +++ b/package-lock.json @@ -982,9 +982,9 @@ } }, "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" From eeebe097f035c0ee8b2bd82f3d9a6c047b0fa04d Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 14 Jun 2026 10:55:53 +0100 Subject: [PATCH 122/123] Version 41 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d86685f..0411a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Version `41` - 2026-06-14 +* Added support for additional trusted proxies via `ADDITIONAL_TRUSTED_PROXIES` by [JackMyers001](https://github.com/mendhak/docker-http-https-echo/pull/101) +* Express update includes the new way of catching all paths + ## Version `40` - 2026-03-20 * Echo back cookies and signed cookies From 2c642afdfe74bec4d7d1ea2284bf2e8b262e5872 Mon Sep 17 00:00:00 2001 From: mendhak Date: Sun, 14 Jun 2026 11:00:10 +0100 Subject: [PATCH 123/123] References updated to v 41 --- README.md | 42 +++++++++++++++++++++--------------------- docker-compose.yml | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index a62686a..92c59a7 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ It comes with various options that can manipulate the response output, see the t ![browser](./screenshots/screenshot.png) -The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:40` -The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:40` +The image is available on [Docker Hub](https://hub.docker.com/r/mendhak/http-https-echo): `mendhak/http-https-echo:41` +The image is available on [Github Container Registry](https://github.com/mendhak/docker-http-https-echo/pkgs/container/http-https-echo): `ghcr.io/mendhak/http-https-echo:41` Please do not use the `:latest` tag as it will break without warning, use a specific version instead. @@ -47,7 +47,7 @@ This image is executed as non root by default and is fully compliant with Kubern Run with Docker - docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 + docker run -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:41 Or run with Docker Compose @@ -64,13 +64,13 @@ You can choose a different internal port instead of 8080 and 8443 with the `HTTP In this example I'm setting http to listen on 8888, and https to listen on 9999. - docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:40 + docker run -e HTTP_PORT=8888 -e HTTPS_PORT=9999 -p 8080:8888 -p 8443:9999 --rm -t mendhak/http-https-echo:41 With docker compose, this would be: my-http-listener: - image: mendhak/http-https-echo:40 + image: mendhak/http-https-echo:41 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999 @@ -86,7 +86,7 @@ The certificates are at `/app/fullchain.pem` and `/app/testpk.pem`. You can use volume mounting to substitute the certificate and private key with your own. my-http-listener: - image: mendhak/http-https-echo:40 + image: mendhak/http-https-echo:41 ports: - "8080:8080" - "8443:8443" @@ -101,14 +101,14 @@ You can use the environment variables `HTTPS_CERT_FILE` and `HTTPS_KEY_FILE` to By default, Express is configured to trust forwarded proxy headers from loopback, link-local, and private IP ranges. To also trust additional proxy IPs or subnets, set `ADDITIONAL_TRUSTED_PROXIES` to a single value or a comma-separated list. - docker run -e ADDITIONAL_TRUSTED_PROXIES="2001:db8::/32,203.0.113.10" -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 + docker run -e ADDITIONAL_TRUSTED_PROXIES="2001:db8::/32,203.0.113.10" -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:41 ## Decode JWT header If you specify the header that contains the JWT, the echo output will contain the decoded JWT. Use the `JWT_HEADER` environment variable for this. - docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:40 + docker run -e JWT_HEADER=Authentication -p 8080:8080 -p 8443:8443 --rm -it mendhak/http-https-echo:41 Now make your request with `Authentication: eyJ...` header (it should also work with the `Authentication: Bearer eyJ...` schema too): @@ -121,7 +121,7 @@ And in the output you should see a `jwt` section. In the log output set the environment variable `DISABLE_REQUEST_LOGS` to true, to disable the specific ExpressJS request log lines. The ones like `::ffff:172.17.0.1 - - [03/Jan/2022:21:31:51 +0000] "GET /xyz HTTP/1.1" 200 423 "-" "curl/7.68.0"`. The JSON output will still appear. - docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 + docker run --rm -e DISABLE_REQUEST_LOGS=true --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 ## Do not log specific path @@ -130,12 +130,12 @@ Set the environment variable `LOG_IGNORE_PATH` to a path or a regex you would li This can help reduce noise from healthchecks in orchestration/infrastructure like Swarm, Kubernetes, ALBs, etc. # Ignore a single path - docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 + docker run -e LOG_IGNORE_PATH=/ping -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:41 # Ignore multiple paths - docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 + docker run -e LOG_IGNORE_PATH="^\/ping|^\/health|^\/metrics" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 # Ignore all paths - docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 - docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 + docker run -e LOG_IGNORE_PATH=".*" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 + docker run -e LOG_IGNORE_PATH="^" -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 @@ -162,7 +162,7 @@ Will contain a `json` property in the response/output. You can disable new lines in the log output by setting the environment variable `LOG_WITHOUT_NEWLINE`. For example, ```bash -docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 +docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:41 ``` ## Send an empty response @@ -170,7 +170,7 @@ docker run -e LOG_WITHOUT_NEWLINE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak You can disable the JSON output in the response by setting the environment variable `ECHO_BACK_TO_CLIENT`. For example, ```bash -docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 +docker run -e ECHO_BACK_TO_CLIENT=false -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:41 ``` ## Custom status code @@ -251,7 +251,7 @@ You can have environment variables (that are visible to the echo server's proces Pass the `ECHO_INCLUDE_ENV_VARS=1` environment variable in. ```bash -docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 +docker run -d --rm -e ECHO_INCLUDE_ENV_VARS=1 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 ``` Then do a normal request via curl or browser, and you will see the `env` property in the response body. @@ -291,7 +291,7 @@ openssl pkcs12 -export -in cert.pem -inkey testpk.pem -out certpkcs12.pfx By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true. ```bash -docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:40 +docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:41 ``` ## Override the response body with a file @@ -300,7 +300,7 @@ To override the response body with a file, set the environment variable `OVERRID The file path needs to be in the `/app` directory. ```bash -docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:40 +docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:41 ``` ## Set a maximum header size @@ -308,7 +308,7 @@ docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_R You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header size in bytes. The default is 1MB. ```bash -docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 +docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 ``` ## Cookies and Signed Cookies @@ -316,7 +316,7 @@ docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak Make a request with a `Cookie` header and the response will include the cookies: ```bash -docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 ``` Then make a request with a cookie header: @@ -328,7 +328,7 @@ curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux" To enable signed cookie support, set the `COOKIE_SECRET` environment variable. Signed cookies appear in the `signedCookies` section of the response: ```bash -docker run -d --rm -e COOKIE_SECRET=mysecretkey123 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:40 +docker run -d --rm -e COOKIE_SECRET=mysecretkey123 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:41 ``` Now you need to generate a signed cookie, and send it in the header. Here's a convenience node snippet: diff --git a/docker-compose.yml b/docker-compose.yml index 2e4fb1d..3250591 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: my-http-listener: - image: mendhak/http-https-echo:40 + image: mendhak/http-https-echo:41 environment: - HTTP_PORT=8888 - HTTPS_PORT=9999