From 31dafd806647b3f69f1550d017469afc8e35b511 Mon Sep 17 00:00:00 2001 From: scastro Date: Sun, 25 Oct 2026 09:04:39 -0600 Subject: [PATCH] =?UTF-8?q?Optimizaciones=20en=20el=20env=C3=ADo=20del=20l?= =?UTF-8?q?ogo=20del=20cliente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 4 +- package-lock.json | 589 +++++++----------- .../welcome/config/SecurityConfiguration.kt | 3 +- .../controller/CustomerLogoController.kt | 41 +- src/main/resources/templates/layout.html | 3 +- .../controller/CustomerLogoControllerTest.kt | 82 +++ 6 files changed, 355 insertions(+), 367 deletions(-) create mode 100644 src/test/kotlin/com/redinterglobal/welcome/controller/CustomerLogoControllerTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 8ceba69..4383ab5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,7 @@ plugins { } group = "com.redinterglobal" -version = "1.3.6-SNAPSHOT" +version = "1.3.7-SNAPSHOT" repositories { mavenCentral() @@ -83,7 +83,7 @@ tasks.named("test") { node { download = true - version = "24.21.0" + version = "26.12.1" } val npmRunBuild = tasks.register("npmRunBuild") { diff --git a/package-lock.json b/package-lock.json index 6f49760..0d71b24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -223,24 +223,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/@jimp/core/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@jimp/core/node_modules/file-type": { "version": "21.3.4", "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", @@ -260,13 +242,6 @@ "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, - "node_modules/@jimp/core/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", - "peer": true - }, "node_modules/@jimp/diff": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.6.1.tgz", @@ -355,16 +330,6 @@ "node": ">=18" } }, - "node_modules/@jimp/js-png/node_modules/pngjs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14.19.0" - } - }, "node_modules/@jimp/js-tiff": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.6.1.tgz", @@ -1506,15 +1471,15 @@ } }, "node_modules/@peculiar/asn1-cms": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.11.0.tgz", - "integrity": "sha512-SlAiDoT/Cd8qaNmbTt78gqyaEvu2fQd6ML6KWJkdjXGrgDKnHHrusVkfQUelkfinL2p665IIADb0JBixtT8W1g==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.11.1.tgz", + "integrity": "sha512-Bk+oatE62dW0Tzzpfk6vdQxfGGEfvuGdWgmijnKjcv7HqZCJISs85z4zw2uDArrk+R1Oel1wts/BBl7HHrtAcA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", - "@peculiar/asn1-x509-attr": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", + "@peculiar/asn1-x509-attr": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1523,14 +1488,14 @@ } }, "node_modules/@peculiar/asn1-csr": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.11.0.tgz", - "integrity": "sha512-M/ED0yJ05qMK+UADPKnIa8vhAeewOJALSxTAZB7RQ/batRHhIJZkwznCcWAbFO5saHJ1yEQ+m4lncEcG9RnQSg==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.11.1.tgz", + "integrity": "sha512-KVfbXaKng8886/tOPG55t5K1XkTkGbR4amjIJzytXWobFU5nZgw/sKnSpa1hxP17nUSsrOF/7Mt9WUYeyLsi6Q==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1539,14 +1504,14 @@ } }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.11.0.tgz", - "integrity": "sha512-jj1alGEKev7/un+cI+exyVK9m31lmP7cCBMCZuCb0wkFQH2zmKmJzNiG4wqXFNzlcP8timHLnzf3lV3OxBpb/Q==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.11.1.tgz", + "integrity": "sha512-7MSNji77fQa/oN3WAfwagMy8EoJFg50sW4hZ1dtr0zU1BSugit0I2DGpIdPhvkNplopQhz5bogxpn1077eaamA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1555,16 +1520,16 @@ } }, "node_modules/@peculiar/asn1-pfx": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.11.0.tgz", - "integrity": "sha512-ykSAWRu8KkmzU8LRpk9ZQC3zuLmBEtoSMjIv9XHVamD5W7amqreV5wttKqnvtjWOzzSJQxA/HVT8/tHwpEEGSQ==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.11.1.tgz", + "integrity": "sha512-2SN2z8qkc2hk/GgTYA8RN54wtsCDZShg9gI2Mq1vLhdj1adcv5fhTbiEmExZUaAMqlizxiEpULQDfHM5iYtn1g==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.11.0", - "@peculiar/asn1-pkcs8": "^2.11.0", - "@peculiar/asn1-rsa": "^2.11.0", - "@peculiar/asn1-schema": "^2.11.0", + "@peculiar/asn1-cms": "^2.11.1", + "@peculiar/asn1-pkcs8": "^2.11.1", + "@peculiar/asn1-rsa": "^2.11.1", + "@peculiar/asn1-schema": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1573,14 +1538,14 @@ } }, "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.11.0.tgz", - "integrity": "sha512-lragjkjQGnQ5luxC+sxoAfAO/jBiQ7hOEGlDKJUk7MC5zY3AzjB2DU0GyPUH1Sswdv10t7DurY0zylOYMLb88w==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.11.1.tgz", + "integrity": "sha512-HqsSrnpQghRp9SM9QSmR6fa4z/BNktnKq7928+oq4qF0VAnuHZ4cyePKvcxh9fP4taBCP/WHNItlVNsYaQm2qw==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1589,18 +1554,18 @@ } }, "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.11.0.tgz", - "integrity": "sha512-gDdFjpqV0weJjgNUvueUVf4D8uVbpq+VbG0TsxLAY2QGljAkJyL9qwQ7avol9j0jaYSJ7Ey7v7RZp0M3GTcQSA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.11.1.tgz", + "integrity": "sha512-OHFkTg8D2zYafILqFE4KPbqX8srpvd3diGDc2h2cduumawc765mOHGcuFMGvLWlL2bbCMWMmMSCtlXptsOuiPA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.11.0", - "@peculiar/asn1-pfx": "^2.11.0", - "@peculiar/asn1-pkcs8": "^2.11.0", - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", - "@peculiar/asn1-x509-attr": "^2.11.0", + "@peculiar/asn1-cms": "^2.11.1", + "@peculiar/asn1-pfx": "^2.11.1", + "@peculiar/asn1-pkcs8": "^2.11.1", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", + "@peculiar/asn1-x509-attr": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1609,14 +1574,14 @@ } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.11.0.tgz", - "integrity": "sha512-S2sBJmbfI09Kzdt9cEhE6pDNjHpVTkURs+811+PxS8AvsTLxC4woMNRhxHYaIbClkkNfAVt0tZxJdINVfUmzuA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.11.1.tgz", + "integrity": "sha512-6KwKGjulF489CpidZqkogNgLj6oGzgC4BL2FClM8PuJQ4t5NqT4q4a6A4vrSxBIBhMnL8hGYkLOpbVw0Vq38Tw==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -1625,9 +1590,9 @@ } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.11.0.tgz", - "integrity": "sha512-8xh4avo53/vXO6UEv9yaoJ83hY581geaLTygf61NPIXP5AeIZCPjJhpTaYU23IZkG+NpLN/C9FYzWp7hphIT9A==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.11.1.tgz", + "integrity": "sha512-jaU9OaCcbZUdyXx9hMETZB9xoNmxTGjOGFqd3cOwKFkpKnyKd9WxF3uqj4PvX4cyOMP9bSdHg5YyML2qtx/d/g==", "dev": true, "license": "MIT", "dependencies": { @@ -1640,13 +1605,13 @@ } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.11.0.tgz", - "integrity": "sha512-J1sHAwGNlk+8J+FeR1eLVc6Gq0T9f9ITc3HWyPYgJraoW6U8AJuQiWVJ3SCEpltfTdpOY7fHdHT5oKAsbK/jww==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.11.1.tgz", + "integrity": "sha512-SXU4/X6B3FquqQAN6ARI0bFDUV7+L1WlvPEPMKzEMkstd2D7UyM0r93fv241+OjdhqAKYGx5MvV3gzZMAp0APA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" @@ -1656,14 +1621,14 @@ } }, "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.11.0.tgz", - "integrity": "sha512-Fgvnd9REmLxEj/4cbDP54dNUNUXkzUksXLqEHqs1mHBuSRjSTCUSPM/WQIZYSvrdG7ND9CX1AQtPoIBekhgQSA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.11.1.tgz", + "integrity": "sha512-n7RKFrbTzt8pGBlZ90kmKEn1qsLTTyw7lrvHMK0xsA42kQugPk/GXYpNbEcl7DkkdVsU/one5UX7KQPfxLj8vQ==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.11.0", - "@peculiar/asn1-x509": "^2.11.0", + "@peculiar/asn1-schema": "^2.11.1", + "@peculiar/asn1-x509": "^2.11.1", "asn1js": "^3.0.10", "tslib": "^2.8.1" }, @@ -2017,31 +1982,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/@tokenizer/inflate/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@tokenizer/inflate/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", - "peer": true - }, "node_modules/@tokenizer/token": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", @@ -2719,9 +2659,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.11.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.29.tgz", - "integrity": "sha512-YeesxhUmR4h5y5V8KF8iBCqJb8YFrBJ++XBTeGcWIaQOYXGN19JM0FoiOjAhwuDoln8owMgXcWBmgHtYSkky2w==", + "version": "2.11.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.32.tgz", + "integrity": "sha512-UvuxFU9P3hM29LrQdwu0cD6w6/+SFr+UlB9s/knI7+O2rK9xFxKUwSDWxGdbbqQ9/V7BJ5s0NI5nQAE4uJp3gQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2746,19 +2686,19 @@ "peer": true }, "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz", + "integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^2.0.0", + "content-type": "^2.1.0", "debug": "^4.4.3", "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", + "iconv-lite": "^0.7.3", "on-finished": "^2.4.1", - "qs": "^6.15.2", + "qs": "^6.16.1", "raw-body": "^3.0.2", "type-is": "^2.1.0" }, @@ -2770,31 +2710,23 @@ "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==", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">=6.0" + "node": ">=0.10.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/bonjour-service": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.4.tgz", @@ -2860,9 +2792,9 @@ } }, "node_modules/browserslist": { - "version": "4.29.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", - "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", + "version": "4.29.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.4.tgz", + "integrity": "sha512-2TcbbiwXEq+N0kD36tykpCfyyQigUXmuwNQbnPp4Xk4PX9JOqVIKjJlIDjpH7uY6tmRGoAd+apeT1p60T8wsdA==", "dev": true, "funding": [ { @@ -2880,11 +2812,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.11.26", - "caniuse-lite": "^1.0.30001813", - "electron-to-chromium": "^1.5.439", - "node-releases": "^2.0.57", - "update-browserslist-db": "^1.3.3" + "baseline-browser-mapping": "^2.11.29", + "caniuse-lite": "^1.0.30001816", + "electron-to-chromium": "^1.5.459", + "node-releases": "^2.0.59", + "update-browserslist-db": "^1.3.4" }, "bin": { "browserslist": "cli.js" @@ -3000,9 +2932,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001816", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001816.tgz", - "integrity": "sha512-+8Yx7BXCoqk6IF8yTicjfUR6D/ldJzdlsodlEOiOSPmhK844WIgk67/zIQaGAOxNkZyyvBlrRFnLvqKIoqbAFw==", + "version": "1.0.30001819", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001819.tgz", + "integrity": "sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==", "dev": true, "funding": [ { @@ -3210,6 +3142,23 @@ "url": "https://opencollective.com/express" } }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -3592,13 +3541,20 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -3786,9 +3742,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.459", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.459.tgz", - "integrity": "sha512-4SC9HHSFjO/liAhifpdOL5hG9b4BP7/5G3y3UPZVO8trlAXr1CaUEEJL0gWK3kOcYcZrOA5rkwG45Gra/lTIgg==", + "version": "1.5.464", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.464.tgz", + "integrity": "sha512-nRa65aFge40viPAKxMKULIY8tcXKwKboJWNn4RoKwyWXJ6SP7BnrDGKUTzc64818jIciH0PK7LSF8QzZes19GA==", "dev": true, "license": "ISC" }, @@ -3995,31 +3951,6 @@ "url": "https://opencollective.com/express" } }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4028,9 +3959,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", - "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", "dev": true, "funding": [ { @@ -4133,31 +4064,6 @@ "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -4433,9 +4339,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-4.2.0.tgz", - "integrity": "sha512-ZA+oNOoM+GLoFTIzhkJptVQov73Srep2LBqhF8hG8CIPKO3nam1jonXVQ/QUH8RbwsmaaVz2SOJdzBNBHNtKbw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-4.2.1.tgz", + "integrity": "sha512-60SmYZpPD4dPbC2GZVkVV4uP/V/cbsXSwzGQXeHWbbE3Q1XdccJpqHTg6NJ6iMpFGVA1OEry8c8kHhx4ahiU1w==", "dev": true, "license": "MIT", "dependencies": { @@ -4449,35 +4355,10 @@ "node": "^22.15.0 || ^24.0.0 || >=26.0.0" } }, - "node_modules/http-proxy-middleware/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-middleware/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==", - "dev": true, - "license": "MIT" - }, "node_modules/httpxy": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.5.5.tgz", - "integrity": "sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.5.6.tgz", + "integrity": "sha512-iqc3nOxvNb5FxbhJozt8wNmHgjlmk4zzba512jMEXVwHCEBCbGAj49eGfy5PI8ts3/LFSFq8siiSNqwfY1AlfQ==", "dev": true, "license": "MIT" }, @@ -4492,9 +4373,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", - "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4502,10 +4383,6 @@ }, "engines": { "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, "node_modules/icss-utils": { @@ -5266,15 +5143,15 @@ } }, "node_modules/minimizer-webpack-plugin": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.13.0.tgz", - "integrity": "sha512-OO1NF2zHj6sf4CNv2AsUWYcS8WEwkVKQDXxxKzlOxx1Xl+WlqYtVC+oNlGNwGkLAOnpj277BSHypWwRtd9w4JQ==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.13.1.tgz", + "integrity": "sha512-1mhAfvachWYYOm8tpmany5NLuvP+F2wxZWBSX8DC0uFS2wJpM9q3rWgN9wBooAH9d5V12wX0BjyJe4fMjHMarQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "jest-worker": "^27.4.5", - "schema-utils": "^4.3.3", + "schema-utils": "^4.6.0", "terser": "^5.51.0" }, "engines": { @@ -5373,10 +5250,9 @@ } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, + "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/multicast-dns": { @@ -5431,9 +5307,9 @@ "optional": true }, "node_modules/node-releases": { - "version": "2.0.59", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.59.tgz", - "integrity": "sha512-5qr2okC4ItAI0hG5SaV0HoYMpnM/Y6+Oqr7AmPYy/2uEoGvS+GbSKLeRxSS1uAdu59yz0ouzcuXievSgg///WA==", + "version": "2.0.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.60.tgz", + "integrity": "sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==", "dev": true, "license": "MIT", "engines": { @@ -5474,9 +5350,9 @@ "peer": true }, "node_modules/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==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.2.tgz", + "integrity": "sha512-ATWUv387i+nLD49EiDoOft5scf32Vsdz3ktrQJG9bi7jRFmaXTssvyvj1EmeKVVgvesbqUtvQQvaS2TpTukAZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5484,6 +5360,10 @@ }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/on-headers": { @@ -5777,9 +5657,9 @@ } }, "node_modules/pkijs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.1.tgz", - "integrity": "sha512-Oo/NZcSWccq8KyoG7gLE9fnltgHns+pNCjCAp/WmjsUySi+sX7y4z4Xqu4fVb42CDHzRPl33fjzT15V1wvcyhA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.3.tgz", + "integrity": "sha512-V9kOzaItwDgqlryhXysQsAXUEKi5O7kqWUaP3dXI7MLvkPqWWMb4wVb1QAtmEDCKI+XIAINsZoNKMFF7sZb1eg==", "dev": true, "license": "BSD-3-Clause", "workspaces": [ @@ -5798,18 +5678,19 @@ } }, "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", "license": "MIT", + "peer": true, "engines": { - "node": ">=10.13.0" + "node": ">=14.19.0" } }, "node_modules/postcss": { - "version": "8.5.30", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.30.tgz", - "integrity": "sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==", + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", "dev": true, "funding": [ { @@ -6338,9 +6219,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", - "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.7.tgz", + "integrity": "sha512-wWBro/7hJ40ye6TPiXkUQoXKCw23xSsjriUvqd7Uls9Sso3oLiON1flc18cCdnjgCRXw4fBVqUJJeOdDTh3P3g==", "dev": true, "license": "MIT", "dependencies": { @@ -6499,6 +6380,15 @@ "node": ">=10.13.0" } }, + "node_modules/qrcode/node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/qs": { "version": "6.16.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.1.tgz", @@ -6546,6 +6436,23 @@ "node": ">= 0.10" } }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/readdirp": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", @@ -6677,31 +6584,6 @@ "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -6744,9 +6626,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.105.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.105.2.tgz", - "integrity": "sha512-KxW6ZKZiBKWK3ziQ4YZ3cpqo8/1TlHXE8t9nBNvGDZFoBFbk2MD7RacxYFs8zy8hzeFwpFYkVyAhboi47uYPEQ==", + "version": "1.106.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.106.1.tgz", + "integrity": "sha512-kD+Gi66vycZcbJt+42NC4z4PXNMcCajVrJPhqoKKXy5cOBMmJQt052CxIBcRjwYXeImHYOpu/ydWWGZQIenl7A==", "dev": true, "license": "MIT", "dependencies": { @@ -6808,9 +6690,9 @@ } }, "node_modules/schema-utils": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.6.0.tgz", - "integrity": "sha512-q8cvkEp4bRQdWcLvB3vmxpZAlS25Hxws10nCK+rUxUfuB7e430dYZZJ5z5yAoOGBbbDtve8cUg8DFfc3ue12TA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.8.1.tgz", + "integrity": "sha512-x39pYlJPyH7Uge5QO64B9XGP9zLDc9WNmiQZc+CE3IzZPvMu3lHOuAMGpYNoPixEL7MSWlGhYTg5UlLSL8G6iw==", "dev": true, "license": "MIT", "dependencies": { @@ -6828,6 +6710,14 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.112.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, "node_modules/selfsigned": { @@ -6884,35 +6774,10 @@ "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/serialize-javascript": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.2.tgz", - "integrity": "sha512-GL2BWwVa6JydKO6l/ljVgjAZF4QJ3S7dWDWi53s5GZT8PJzD2fNxi67HANQGKAqPrwEpL5ba7gUBGi0Ls/sEoQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.4.tgz", + "integrity": "sha512-FqlEuoTq/zRmA4Lg6aOqyH3lCHbUtCB0bmHCeFniX2GBdDqMJM3FwdvEhlE5Pim1dlt2FfBdVPmUNNiGhhKqpw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -6956,6 +6821,16 @@ "node": ">= 0.6" } }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -7006,6 +6881,13 @@ "node": ">= 0.6" } }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/serve-index/node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -7248,19 +7130,6 @@ "webpack": "^5.72.1" } }, - "node_modules/source-map-loader/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -7716,9 +7585,9 @@ } }, "node_modules/watchpack": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.6.2.tgz", - "integrity": "sha512-67nxRd7I5uAyn+KamYsCqU30iVgCgZ4aj8ZOGzmxs7zNPuvlnoYltm6+6JkOjEcD6WVXdu1BfH+gVQs3FUuW7Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.6.3.tgz", + "integrity": "sha512-s3NZy0QpTY9qGqzc0wtz4qI28z3+5qKbbAec4MV4G9N3CfgZ9wgvQRr0cl2jh/tqkWG1NWHkmVMHZpCamev5Wg==", "dev": true, "license": "MIT", "dependencies": { @@ -7729,9 +7598,9 @@ } }, "node_modules/webpack": { - "version": "5.112.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.112.0.tgz", - "integrity": "sha512-NIBpsRuCll036haDDt/CfcTDfsWNR9Z782nMRMI9D377BsGcYzZDTNU5TyzhCJzPIcihAxMBaMAhq2WSaDrH8Q==", + "version": "5.112.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.112.2.tgz", + "integrity": "sha512-B2tp1LI9D8GVpPDqprdt12ukTkXXahj9MzqSWJq4faSPgOUM7CdZaGAB6HrL/8E6UwbBpdj4vzWDbKoFnVoU6g==", "dev": true, "license": "MIT", "dependencies": { @@ -7748,9 +7617,9 @@ "graceful-fs": "^4.2.11", "mime-db": "^1.54.0", "minimizer-webpack-plugin": "^5.13.0", - "schema-utils": "^4.5.0", + "schema-utils": "^4.8.1", "tapable": "^2.3.0", - "watchpack": "^2.6.1", + "watchpack": "^2.6.3", "webpack-sources": "^3.6.0" }, "bin": { @@ -7813,9 +7682,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-8.4.0.tgz", - "integrity": "sha512-a/YonExZBacvdZUdVmIFYJ4GbX8FaHXZFdEgQv9T24KBvrVW1zI2wVoWBxalpCW+rNm5rzfNBtFbHIYwypV/lQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-8.5.0.tgz", + "integrity": "sha512-+rXF28E5GKr7VnLH5qJaGIKLNPkthlA0VhqBFp/K6mjjCzOd6q34vYc2/3/ysRTjxmN01S98r1LwTTpWXDzWWA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/src/main/kotlin/com/redinterglobal/welcome/config/SecurityConfiguration.kt b/src/main/kotlin/com/redinterglobal/welcome/config/SecurityConfiguration.kt index 65a4908..6a5d1c2 100644 --- a/src/main/kotlin/com/redinterglobal/welcome/config/SecurityConfiguration.kt +++ b/src/main/kotlin/com/redinterglobal/welcome/config/SecurityConfiguration.kt @@ -72,7 +72,7 @@ class SecurityConfiguration { monitorAuthenticationSuccessHandler: MonitorAuthenticationSuccessHandler ): SecurityFilterChain { http { - securityMatcher("/monitor", "/monitor/**", "/oauth2/**", "/login/oauth2/**") + securityMatcher("/monitor/**", "/oauth2/**", "/login/oauth2/**") authorizeHttpRequests { authorize(unmappedControllerRequestMatcher, permitAll) authorize("/monitor/login", permitAll) @@ -115,6 +115,7 @@ class SecurityConfiguration { http { authorizeHttpRequests { authorize(unmappedControllerRequestMatcher, permitAll) + authorize("/logo", authenticated) authorize("/error/**", permitAll) authorize("/css/**", permitAll) authorize("/js/**", permitAll) diff --git a/src/main/kotlin/com/redinterglobal/welcome/controller/CustomerLogoController.kt b/src/main/kotlin/com/redinterglobal/welcome/controller/CustomerLogoController.kt index c24ecf3..8f99295 100644 --- a/src/main/kotlin/com/redinterglobal/welcome/controller/CustomerLogoController.kt +++ b/src/main/kotlin/com/redinterglobal/welcome/controller/CustomerLogoController.kt @@ -13,20 +13,28 @@ package com.redinterglobal.welcome.controller import com.redinterglobal.welcome.config.SdoAuthenticationPrincipal +import com.redinterglobal.welcome.service.Logo import com.redinterglobal.welcome.service.SdoService +import jakarta.servlet.http.HttpServletRequest +import org.springframework.http.CacheControl +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.context.request.ServletWebRequest +import java.security.MessageDigest import java.security.Principal +import java.util.concurrent.TimeUnit @Controller class CustomerLogoController( private val sdoService: SdoService ) { @GetMapping("/logo", "/monitor/logo") - fun logo(principal: Principal): ResponseEntity { + fun logo(principal: Principal, request: HttpServletRequest): ResponseEntity { val registrationId = if (principal is UsernamePasswordAuthenticationToken && principal.principal is SdoAuthenticationPrincipal) { val user = principal.principal as SdoAuthenticationPrincipal @@ -36,6 +44,35 @@ class CustomerLogoController( } else null val logo = if (registrationId != null) sdoService.logo(registrationId) else null - return if (logo != null) ResponseEntity.ok().contentType(logo.mediaType).body(logo.media) else ResponseEntity.notFound().build() + if (logo == null) { + return ResponseEntity.notFound() + .header(HttpHeaders.CACHE_CONTROL, "no-store") + .build() + } + + val eTag = logo.eTag() + val cacheControl = CacheControl.maxAge(1, TimeUnit.DAYS).cachePrivate().mustRevalidate() + if (ServletWebRequest(request).checkNotModified(eTag)) { + return ResponseEntity.status(HttpStatus.NOT_MODIFIED) + .eTag(eTag) + .cacheControl(cacheControl) + .header(HttpHeaders.VARY, HttpHeaders.COOKIE) + .build() + } + + return ResponseEntity.ok() + .contentType(logo.mediaType) + .eTag(eTag) + .cacheControl(cacheControl) + .header(HttpHeaders.VARY, HttpHeaders.COOKIE) + .body(logo.media) + } + + private fun Logo.eTag(): String { + val digest = MessageDigest.getInstance("SHA-256") + digest.update(mediaType.toString().toByteArray(Charsets.UTF_8)) + digest.update(0) + digest.update(media) + return digest.digest().joinToString("") { "%02x".format(it) } } } diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html index 18351a4..9e9005b 100644 --- a/src/main/resources/templates/layout.html +++ b/src/main/resources/templates/layout.html @@ -48,8 +48,7 @@
- - +
diff --git a/src/test/kotlin/com/redinterglobal/welcome/controller/CustomerLogoControllerTest.kt b/src/test/kotlin/com/redinterglobal/welcome/controller/CustomerLogoControllerTest.kt new file mode 100644 index 0000000..e5e29df --- /dev/null +++ b/src/test/kotlin/com/redinterglobal/welcome/controller/CustomerLogoControllerTest.kt @@ -0,0 +1,82 @@ +package com.redinterglobal.welcome.controller + +import com.redinterglobal.sdo.domain.User +import com.redinterglobal.welcome.config.SdoAuthenticationPrincipal +import com.redinterglobal.welcome.service.Logo +import com.redinterglobal.welcome.service.SdoService +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken + +class CustomerLogoControllerTest { + + @Test + fun `logo response is privately cacheable and includes an ETag`() { + val logo = Logo(MediaType.IMAGE_PNG, byteArrayOf(1, 2, 3)) + val response = logoResponse(logo) + + assertEquals(200, response.statusCode.value()) + assertEquals(MediaType.IMAGE_PNG, response.headers.contentType) + assertContentEquals(logo.media, requireNotNull(response.body)) + assertEquals("max-age=86400, must-revalidate, private", response.headers.cacheControl) + assertEquals(HttpHeaders.COOKIE, response.headers.getFirst(HttpHeaders.VARY)) + requireNotNull(response.headers.eTag) + } + + @Test + fun `matching ETag returns not modified without a body`() { + val logo = Logo(MediaType.IMAGE_PNG, byteArrayOf(1, 2, 3)) + val initial = logoResponse(logo) + val request = MockHttpServletRequest().apply { + addHeader(HttpHeaders.IF_NONE_MATCH, requireNotNull(initial.headers.eTag)) + } + + val response = controller(logo).logo(authentication(), request) + + assertEquals(304, response.statusCode.value()) + assertNull(response.body) + assertEquals(initial.headers.eTag, response.headers.eTag) + assertEquals("max-age=86400, must-revalidate, private", response.headers.cacheControl) + } + + @Test + fun `changed logo produces a new ETag`() { + val initial = logoResponse(Logo(MediaType.IMAGE_PNG, byteArrayOf(1, 2, 3))) + val changed = logoResponse(Logo(MediaType.IMAGE_PNG, byteArrayOf(4, 5, 6))) + + assertNotEquals(initial.headers.eTag, changed.headers.eTag) + } + + @Test + fun `missing logo is not cached`() { + val service = mock(SdoService::class.java) + `when`(service.logo("registration")).thenReturn(null) + + val response = CustomerLogoController(service).logo(authentication(), MockHttpServletRequest()) + + assertEquals(404, response.statusCode.value()) + assertEquals("no-store", response.headers.cacheControl) + } + + private fun logoResponse(logo: Logo) = + controller(logo).logo(authentication(), MockHttpServletRequest()) + + private fun controller(logo: Logo): CustomerLogoController { + val service = mock(SdoService::class.java) + `when`(service.logo("registration")).thenReturn(logo) + return CustomerLogoController(service) + } + + private fun authentication() = UsernamePasswordAuthenticationToken( + SdoAuthenticationPrincipal(mock(User::class.java), "registration"), + null + ) +}