diff --git a/.env b/.env index 8311abad..8cd39f31 100644 --- a/.env +++ b/.env @@ -149,6 +149,16 @@ DISABLE_YEAR2038_BUG_CHECK=0 #TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 #TRUSTED_HOSTS='^(localhost|example\.com)$' +################################################################################### +# Logging settings +################################################################################### + +# The minimum level a deprecation notice must have to be written to the var/log/_deprecations.log file. +# Deprecation notices are logged with level "info", so this disables the deprecation log by default. +# Set to debug to log all deprecation notices +DEPRECATION_LOG_LEVEL=emergency + + ###> symfony/lock ### # Choose one of the stores below diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5b756228..27dfe173 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -129,7 +129,7 @@ jobs: run: ./bin/phpunit --coverage-clover=coverage.xml - name: Upload coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: env_vars: PHP_VERSION,DB_TYPE token: ${{ secrets.CODECOV_TOKEN }} diff --git a/VERSION b/VERSION index 3cf561c0..371a952d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.12.1 +2.12.2 diff --git a/assets/controllers/common/hide_sidebar_controller.js b/assets/controllers/common/hide_sidebar_controller.js index 4be304ff..c65cdcdf 100644 --- a/assets/controllers/common/hide_sidebar_controller.js +++ b/assets/controllers/common/hide_sidebar_controller.js @@ -51,7 +51,7 @@ export default class extends Controller { //Make the state persistent over reloads if(localStorage.getItem(STORAGE_KEY) === 'true') { - sidebarHide(); + this.hideSidebar(); } } diff --git a/composer.json b/composer.json index a1f15834..f08f824d 100644 --- a/composer.json +++ b/composer.json @@ -70,6 +70,7 @@ "symfony/flex": "^v2.3.1", "symfony/form": "7.4.*", "symfony/framework-bundle": "7.4.*", + "symfony/html-sanitizer": "7.4.*", "symfony/http-client": "7.4.*", "symfony/http-kernel": "7.4.*", "symfony/mailer": "7.4.*", diff --git a/composer.lock b/composer.lock index 1c2f7dda..71918b0f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d6bda397c505e1e6d540c814a2368fbb", + "content-hash": "1307bf553d1543704e3c03398dec06c7", "packages": [ { "name": "amphp/amp", @@ -976,7 +976,7 @@ }, { "name": "api-platform/doctrine-common", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/doctrine-common.git", @@ -1060,22 +1060,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/doctrine-common/tree/v4.3.10" + "source": "https://github.com/api-platform/doctrine-common/tree/v4.3.13" }, "time": "2026-06-05T09:05:29+00:00" }, { "name": "api-platform/doctrine-orm", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/doctrine-orm.git", - "reference": "db75bac977cc9fe76cee90c1e5361c744cfa2144" + "reference": "7d8851966a55d2f53e4d86b281ba543fa14e953b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/doctrine-orm/zipball/db75bac977cc9fe76cee90c1e5361c744cfa2144", - "reference": "db75bac977cc9fe76cee90c1e5361c744cfa2144", + "url": "https://api.github.com/repos/api-platform/doctrine-orm/zipball/7d8851966a55d2f53e4d86b281ba543fa14e953b", + "reference": "7d8851966a55d2f53e4d86b281ba543fa14e953b", "shasum": "" }, "require": { @@ -1149,13 +1149,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/doctrine-orm/tree/v4.3.10" + "source": "https://github.com/api-platform/doctrine-orm/tree/v4.3.13" }, - "time": "2026-06-04T13:58:17+00:00" + "time": "2026-06-13T04:46:03+00:00" }, { "name": "api-platform/documentation", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/documentation.git", @@ -1212,22 +1212,22 @@ ], "description": "API Platform documentation controller.", "support": { - "source": "https://github.com/api-platform/documentation/tree/v4.3.10" + "source": "https://github.com/api-platform/documentation/tree/v4.3.13" }, "time": "2026-04-30T12:21:24+00:00" }, { "name": "api-platform/http-cache", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/http-cache.git", - "reference": "98e5ba9344abe9db7d6789429745ee4eb0a2fd8f" + "reference": "8e71916de766f503dd60f1a1e886b4d704f881a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/http-cache/zipball/98e5ba9344abe9db7d6789429745ee4eb0a2fd8f", - "reference": "98e5ba9344abe9db7d6789429745ee4eb0a2fd8f", + "url": "https://api.github.com/repos/api-platform/http-cache/zipball/8e71916de766f503dd60f1a1e886b4d704f881a8", + "reference": "8e71916de766f503dd60f1a1e886b4d704f881a8", "shasum": "" }, "require": { @@ -1292,22 +1292,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/http-cache/tree/v4.3.10" + "source": "https://github.com/api-platform/http-cache/tree/v4.3.13" }, - "time": "2026-05-29T13:58:43+00:00" + "time": "2026-06-09T14:20:49+00:00" }, { "name": "api-platform/hydra", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/hydra.git", - "reference": "a0314c8dda95f69f15054d7309ddbc1ca32f2149" + "reference": "c9c53cfc9cdf9a2b8499d49dc70cf3ea9dbf8463" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/hydra/zipball/a0314c8dda95f69f15054d7309ddbc1ca32f2149", - "reference": "a0314c8dda95f69f15054d7309ddbc1ca32f2149", + "url": "https://api.github.com/repos/api-platform/hydra/zipball/c9c53cfc9cdf9a2b8499d49dc70cf3ea9dbf8463", + "reference": "c9c53cfc9cdf9a2b8499d49dc70cf3ea9dbf8463", "shasum": "" }, "require": { @@ -1315,7 +1315,7 @@ "api-platform/json-schema": "^4.3", "api-platform/jsonld": "^4.3", "api-platform/metadata": "^4.3", - "api-platform/serializer": "^4.3", + "api-platform/serializer": "^4.3.12", "api-platform/state": "^4.3", "php": ">=8.2", "symfony/type-info": "^7.3 || ^8.0", @@ -1379,29 +1379,29 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/hydra/tree/v4.3.10" + "source": "https://github.com/api-platform/hydra/tree/v4.3.13" }, - "time": "2026-06-04T13:52:24+00:00" + "time": "2026-06-13T05:11:46+00:00" }, { "name": "api-platform/json-api", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/json-api.git", - "reference": "2e1773bc4b098119531c59de14124afa0cb693a2" + "reference": "dbff4fd044b131c63fe7540da796e01cda2814d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/json-api/zipball/2e1773bc4b098119531c59de14124afa0cb693a2", - "reference": "2e1773bc4b098119531c59de14124afa0cb693a2", + "url": "https://api.github.com/repos/api-platform/json-api/zipball/dbff4fd044b131c63fe7540da796e01cda2814d2", + "reference": "dbff4fd044b131c63fe7540da796e01cda2814d2", "shasum": "" }, "require": { "api-platform/documentation": "^4.3", "api-platform/json-schema": "^4.3", "api-platform/metadata": "^4.3", - "api-platform/serializer": "^4.3.8", + "api-platform/serializer": "^4.3.12", "api-platform/state": "^4.3", "php": ">=8.2", "symfony/error-handler": "^6.4 || ^7.0 || ^8.0", @@ -1461,22 +1461,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/json-api/tree/v4.3.10" + "source": "https://github.com/api-platform/json-api/tree/v4.3.13" }, - "time": "2026-06-05T15:17:34+00:00" + "time": "2026-06-13T05:11:46+00:00" }, { "name": "api-platform/json-schema", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/json-schema.git", - "reference": "6a0a2ddc4914bb1fdb1b71777c49aef388f6ea31" + "reference": "2136965a30643056d09b10ae5e9fab1f7232a028" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/json-schema/zipball/6a0a2ddc4914bb1fdb1b71777c49aef388f6ea31", - "reference": "6a0a2ddc4914bb1fdb1b71777c49aef388f6ea31", + "url": "https://api.github.com/repos/api-platform/json-schema/zipball/2136965a30643056d09b10ae5e9fab1f7232a028", + "reference": "2136965a30643056d09b10ae5e9fab1f7232a028", "shasum": "" }, "require": { @@ -1542,27 +1542,27 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/json-schema/tree/v4.3.10" + "source": "https://github.com/api-platform/json-schema/tree/v4.3.13" }, - "time": "2026-06-03T14:46:27+00:00" + "time": "2026-06-13T05:06:55+00:00" }, { "name": "api-platform/jsonld", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/jsonld.git", - "reference": "20ca6d7b5c11674c3046d710aaa0c9bc1795e54b" + "reference": "026a380c3c85c4210028da43e0cea1b64211bbf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/jsonld/zipball/20ca6d7b5c11674c3046d710aaa0c9bc1795e54b", - "reference": "20ca6d7b5c11674c3046d710aaa0c9bc1795e54b", + "url": "https://api.github.com/repos/api-platform/jsonld/zipball/026a380c3c85c4210028da43e0cea1b64211bbf5", + "reference": "026a380c3c85c4210028da43e0cea1b64211bbf5", "shasum": "" }, "require": { "api-platform/metadata": "^4.3", - "api-platform/serializer": "^4.3", + "api-platform/serializer": "^4.3.12", "api-platform/state": "^4.3", "php": ">=8.2" }, @@ -1622,22 +1622,22 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/jsonld/tree/v4.3.10" + "source": "https://github.com/api-platform/jsonld/tree/v4.3.13" }, - "time": "2026-04-30T12:21:24+00:00" + "time": "2026-06-13T05:11:46+00:00" }, { "name": "api-platform/metadata", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/metadata.git", - "reference": "b835ce534861f9e7b2a316fa582f28afe4ad5fe6" + "reference": "86efa5375e994f4e46f3e4336dc4dc5ecc9456a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/metadata/zipball/b835ce534861f9e7b2a316fa582f28afe4ad5fe6", - "reference": "b835ce534861f9e7b2a316fa582f28afe4ad5fe6", + "url": "https://api.github.com/repos/api-platform/metadata/zipball/86efa5375e994f4e46f3e4336dc4dc5ecc9456a8", + "reference": "86efa5375e994f4e46f3e4336dc4dc5ecc9456a8", "shasum": "" }, "require": { @@ -1720,22 +1720,22 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/metadata/tree/v4.3.10" + "source": "https://github.com/api-platform/metadata/tree/v4.3.13" }, - "time": "2026-06-05T09:05:29+00:00" + "time": "2026-06-13T05:03:21+00:00" }, { "name": "api-platform/openapi", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/openapi.git", - "reference": "21e22f4d74fafc4b01ee5790be7a264387445dcf" + "reference": "07c9e5c7325f810cea0cc1821ff564dbae6e57d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/openapi/zipball/21e22f4d74fafc4b01ee5790be7a264387445dcf", - "reference": "21e22f4d74fafc4b01ee5790be7a264387445dcf", + "url": "https://api.github.com/repos/api-platform/openapi/zipball/07c9e5c7325f810cea0cc1821ff564dbae6e57d5", + "reference": "07c9e5c7325f810cea0cc1821ff564dbae6e57d5", "shasum": "" }, "require": { @@ -1753,7 +1753,7 @@ "api-platform/doctrine-common": "^4.3", "api-platform/doctrine-odm": "^4.3", "api-platform/doctrine-orm": "^4.3", - "api-platform/serializer": "^4.3", + "api-platform/serializer": "^4.3.12", "phpspec/prophecy-phpunit": "^2.2", "phpunit/phpunit": "^11.5 || ^12.2", "symfony/type-info": "^7.3 || ^8.0" @@ -1811,22 +1811,22 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/openapi/tree/v4.3.10" + "source": "https://github.com/api-platform/openapi/tree/v4.3.13" }, - "time": "2026-06-03T14:37:29+00:00" + "time": "2026-06-13T05:11:46+00:00" }, { "name": "api-platform/serializer", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/serializer.git", - "reference": "04d56abff2910390111613716cd75796f23e34d5" + "reference": "69042d5861779066b54bca1f6356bf5fe0eed466" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/serializer/zipball/04d56abff2910390111613716cd75796f23e34d5", - "reference": "04d56abff2910390111613716cd75796f23e34d5", + "url": "https://api.github.com/repos/api-platform/serializer/zipball/69042d5861779066b54bca1f6356bf5fe0eed466", + "reference": "69042d5861779066b54bca1f6356bf5fe0eed466", "shasum": "" }, "require": { @@ -1905,22 +1905,22 @@ "serializer" ], "support": { - "source": "https://github.com/api-platform/serializer/tree/v4.3.10" + "source": "https://github.com/api-platform/serializer/tree/v4.3.13" }, - "time": "2026-06-05T12:07:51+00:00" + "time": "2026-06-13T05:11:46+00:00" }, { "name": "api-platform/state", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/state.git", - "reference": "06067bf0efae09badc618fac8add67191f12f1e3" + "reference": "3bb76df0857dd1a6e706dd1c5c4b574432a2fa8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/state/zipball/06067bf0efae09badc618fac8add67191f12f1e3", - "reference": "06067bf0efae09badc618fac8add67191f12f1e3", + "url": "https://api.github.com/repos/api-platform/state/zipball/3bb76df0857dd1a6e706dd1c5c4b574432a2fa8d", + "reference": "3bb76df0857dd1a6e706dd1c5c4b574432a2fa8d", "shasum": "" }, "require": { @@ -1933,7 +1933,7 @@ "symfony/translation-contracts": "^3.0" }, "require-dev": { - "api-platform/serializer": "^4.3", + "api-platform/serializer": "^4.3.12", "api-platform/validator": "^4.3.1", "phpunit/phpunit": "^11.5 || ^12.2", "symfony/http-foundation": "^6.4.14 || ^7.0 || ^8.0", @@ -2002,22 +2002,22 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/state/tree/v4.3.10" + "source": "https://github.com/api-platform/state/tree/v4.3.13" }, - "time": "2026-06-05T15:16:47+00:00" + "time": "2026-06-13T05:11:46+00:00" }, { "name": "api-platform/symfony", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/symfony.git", - "reference": "70a1a4468d77c9761ac1a6cba681277fa986c39b" + "reference": "358668b0de7c4a214d477a30fe83deab2a5da96c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/symfony/zipball/70a1a4468d77c9761ac1a6cba681277fa986c39b", - "reference": "70a1a4468d77c9761ac1a6cba681277fa986c39b", + "url": "https://api.github.com/repos/api-platform/symfony/zipball/358668b0de7c4a214d477a30fe83deab2a5da96c", + "reference": "358668b0de7c4a214d477a30fe83deab2a5da96c", "shasum": "" }, "require": { @@ -2028,7 +2028,7 @@ "api-platform/jsonld": "^4.3", "api-platform/metadata": "^4.3", "api-platform/openapi": "^4.3", - "api-platform/serializer": "^4.3", + "api-platform/serializer": "^4.3.12", "api-platform/state": "^4.3", "api-platform/validator": "^4.3.1", "php": ">=8.2", @@ -2131,13 +2131,13 @@ "symfony" ], "support": { - "source": "https://github.com/api-platform/symfony/tree/v4.3.10" + "source": "https://github.com/api-platform/symfony/tree/v4.3.13" }, - "time": "2026-06-05T15:17:34+00:00" + "time": "2026-06-13T05:21:29+00:00" }, { "name": "api-platform/validator", - "version": "v4.3.10", + "version": "v4.3.13", "source": { "type": "git", "url": "https://github.com/api-platform/validator.git", @@ -2207,22 +2207,22 @@ "validator" ], "support": { - "source": "https://github.com/api-platform/validator/tree/v4.3.10" + "source": "https://github.com/api-platform/validator/tree/v4.3.13" }, "time": "2026-05-07T11:45:31+00:00" }, { "name": "beberlei/assert", - "version": "v3.3.3", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd" + "reference": "f193f4613c7d7fbcee2c05e4daff4061d49c040e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/b5fd8eacd8915a1b627b8bfc027803f1939734dd", - "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd", + "url": "https://api.github.com/repos/beberlei/assert/zipball/f193f4613c7d7fbcee2c05e4daff4061d49c040e", + "reference": "f193f4613c7d7fbcee2c05e4daff4061d49c040e", "shasum": "" }, "require": { @@ -2274,9 +2274,9 @@ ], "support": { "issues": "https://github.com/beberlei/assert/issues", - "source": "https://github.com/beberlei/assert/tree/v3.3.3" + "source": "https://github.com/beberlei/assert/tree/v3.3.4" }, - "time": "2024-07-15T13:18:35+00:00" + "time": "2026-06-10T19:47:05+00:00" }, { "name": "beberlei/doctrineextensions", @@ -2658,28 +2658,29 @@ }, { "name": "composer/pcre", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.10" + "phpstan/phpstan": "<2.2.2" }, "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9" }, "type": "library", "extra": { @@ -2717,7 +2718,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" + "source": "https://github.com/composer/pcre/tree/3.4.0" }, "funding": [ { @@ -2727,13 +2728,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2024-11-12T16:29:46+00:00" + "time": "2026-06-07T11:47:49+00:00" }, { "name": "composer/semver", @@ -3349,16 +3346,16 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.18.2", + "version": "2.18.3", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546" + "reference": "241d61f6bbc77275d5a9f95d514241c058bf2d0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/0ff098b29b8b3c68307c8987dcaed7fd829c6546", - "reference": "0ff098b29b8b3c68307c8987dcaed7fd829c6546", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/241d61f6bbc77275d5a9f95d514241c058bf2d0a", + "reference": "241d61f6bbc77275d5a9f95d514241c058bf2d0a", "shasum": "" }, "require": { @@ -3395,6 +3392,7 @@ "psr/log": "^1.1.4 || ^2.0 || ^3.0", "symfony/doctrine-messenger": "^6.4 || ^7.0", "symfony/expression-language": "^6.4 || ^7.0", + "symfony/http-kernel": "^6.4 || ^7.0", "symfony/messenger": "^6.4 || ^7.0", "symfony/property-info": "^6.4 || ^7.0", "symfony/security-bundle": "^6.4 || ^7.0", @@ -3450,7 +3448,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.18.2" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.18.3" }, "funding": [ { @@ -3466,7 +3464,7 @@ "type": "tidelift" } ], - "time": "2025-12-20T21:35:32+00:00" + "time": "2026-06-08T08:22:50+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -4637,16 +4635,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.11.0", + "version": "7.11.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "c987f8ce84b8434fa430795eca0f3430663da72b" + "reference": "5af96f374e0ab4ebd747b8310888c99d3adb0a8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/c987f8ce84b8434fa430795eca0f3430663da72b", - "reference": "c987f8ce84b8434fa430795eca0f3430663da72b", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/5af96f374e0ab4ebd747b8310888c99d3adb0a8c", + "reference": "5af96f374e0ab4ebd747b8310888c99d3adb0a8c", "shasum": "" }, "require": { @@ -4665,7 +4663,7 @@ "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", "guzzle/client-integration-tests": "3.0.2", - "guzzlehttp/test-server": "^0.4", + "guzzlehttp/test-server": "^0.5", "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.52 || ^9.6.34", "psr/log": "^1.1 || ^2.0 || ^3.0" @@ -4745,7 +4743,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.11.0" + "source": "https://github.com/guzzle/guzzle/tree/7.11.1" }, "funding": [ { @@ -4761,7 +4759,7 @@ "type": "tidelift" } ], - "time": "2026-06-02T12:40:51+00:00" + "time": "2026-06-07T22:54:06+00:00" }, { "name": "guzzlehttp/promises", @@ -10140,16 +10138,16 @@ }, { "name": "scheb/2fa-backup-code", - "version": "v7.13.1", + "version": "v7.14.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-backup-code.git", - "reference": "35f1ace4be7be2c10158d2bb8284208499111db8" + "reference": "73946182322f43cf82c5ee8c5481481a570ade40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/35f1ace4be7be2c10158d2bb8284208499111db8", - "reference": "35f1ace4be7be2c10158d2bb8284208499111db8", + "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/73946182322f43cf82c5ee8c5481481a570ade40", + "reference": "73946182322f43cf82c5ee8c5481481a570ade40", "shasum": "" }, "require": { @@ -10183,22 +10181,22 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-backup-code/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-backup-code/tree/v7.14.0" }, - "time": "2025-11-20T13:35:24+00:00" + "time": "2026-01-24T13:47:32+00:00" }, { "name": "scheb/2fa-bundle", - "version": "v7.13.1", + "version": "v7.14.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-bundle.git", - "reference": "edcc14456b508aab37ec792cfc36793d04226784" + "reference": "65fa9eb61d1205f2024f14c8c38b53e7bb20927c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/edcc14456b508aab37ec792cfc36793d04226784", - "reference": "edcc14456b508aab37ec792cfc36793d04226784", + "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/65fa9eb61d1205f2024f14c8c38b53e7bb20927c", + "reference": "65fa9eb61d1205f2024f14c8c38b53e7bb20927c", "shasum": "" }, "require": { @@ -10251,22 +10249,22 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-bundle/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-bundle/tree/v7.14.0" }, - "time": "2025-12-18T15:29:07+00:00" + "time": "2026-06-12T18:31:07+00:00" }, { "name": "scheb/2fa-google-authenticator", - "version": "v7.13.1", + "version": "v7.14.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-google-authenticator.git", - "reference": "7ad34bbde343a0770571464127ee072aacb70a58" + "reference": "23b0bda5b924b8752047c4994f10e1c9e1532179" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-google-authenticator/zipball/7ad34bbde343a0770571464127ee072aacb70a58", - "reference": "7ad34bbde343a0770571464127ee072aacb70a58", + "url": "https://api.github.com/repos/scheb/2fa-google-authenticator/zipball/23b0bda5b924b8752047c4994f10e1c9e1532179", + "reference": "23b0bda5b924b8752047c4994f10e1c9e1532179", "shasum": "" }, "require": { @@ -10304,22 +10302,22 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-google-authenticator/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-google-authenticator/tree/v7.14.0" }, - "time": "2025-12-04T15:55:14+00:00" + "time": "2026-01-24T13:53:55+00:00" }, { "name": "scheb/2fa-trusted-device", - "version": "v7.13.1", + "version": "v7.14.0", "source": { "type": "git", "url": "https://github.com/scheb/2fa-trusted-device.git", - "reference": "ae3a5819faccbf151af078f432e4e6c97bb44ebf" + "reference": "590f400bac58bff70af24adbc702e57a30e493a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-trusted-device/zipball/ae3a5819faccbf151af078f432e4e6c97bb44ebf", - "reference": "ae3a5819faccbf151af078f432e4e6c97bb44ebf", + "url": "https://api.github.com/repos/scheb/2fa-trusted-device/zipball/590f400bac58bff70af24adbc702e57a30e493a3", + "reference": "590f400bac58bff70af24adbc702e57a30e493a3", "shasum": "" }, "require": { @@ -10355,9 +10353,9 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-trusted-device/tree/v7.13.1" + "source": "https://github.com/scheb/2fa-trusted-device/tree/v7.14.0" }, - "time": "2025-12-01T15:40:59+00:00" + "time": "2026-01-24T13:47:32+00:00" }, { "name": "shivas/versioning-bundle", @@ -13094,6 +13092,80 @@ ], "time": "2026-05-23T18:04:28+00:00" }, + { + "name": "symfony/html-sanitizer", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/html-sanitizer.git", + "reference": "761f6c49dfd103ee08b3cd09ece588b069e18ec9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/761f6c49dfd103ee08b3cd09ece588b069e18ec9", + "reference": "761f6c49dfd103ee08b3cd09ece588b069e18ec9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "league/uri": "^6.5|^7.0", + "masterminds/html5": "^2.7.2", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HtmlSanitizer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Titouan Galopin", + "email": "galopintitouan@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to sanitize untrusted HTML input for safe insertion into a document's DOM.", + "homepage": "https://symfony.com", + "keywords": [ + "Purifier", + "html", + "sanitizer" + ], + "support": { + "source": "https://github.com/symfony/html-sanitizer/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-24T11:20:33+00:00" + }, { "name": "symfony/http-client", "version": "v7.4.13", @@ -14477,16 +14549,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.38.1", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "8339098cae28673c15cce00d80734af0453054e2" + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/8339098cae28673c15cce00d80734af0453054e2", - "reference": "8339098cae28673c15cce00d80734af0453054e2", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/796a26abb75ce49f3a84433cd81bf1009d73d5f8", + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8", "shasum": "" }, "require": { @@ -14533,7 +14605,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.2" }, "funding": [ { @@ -14553,7 +14625,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T12:51:13+00:00" + "time": "2026-05-27T06:51:48+00:00" }, { "name": "symfony/polyfill-php84", @@ -17400,16 +17472,16 @@ }, { "name": "symplify/easy-coding-standard", - "version": "13.1.5", + "version": "13.2.2", "source": { "type": "git", - "url": "https://github.com/easy-coding-standard/ecs.git", - "reference": "96294d652c17ccffabb7d36f9d116dd5f0e6b84e" + "url": "https://github.com/ecsphp/ecs.git", + "reference": "3da31a9c267ead69664eb1258aaea62bf9b66f79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/easy-coding-standard/ecs/zipball/96294d652c17ccffabb7d36f9d116dd5f0e6b84e", - "reference": "96294d652c17ccffabb7d36f9d116dd5f0e6b84e", + "url": "https://api.github.com/repos/ecsphp/ecs/zipball/3da31a9c267ead69664eb1258aaea62bf9b66f79", + "reference": "3da31a9c267ead69664eb1258aaea62bf9b66f79", "shasum": "" }, "require": { @@ -17444,9 +17516,9 @@ "static analysis" ], "support": { - "source": "https://github.com/easy-coding-standard/ecs/tree/13.1.5" + "source": "https://github.com/ecsphp/ecs/tree/13.2.2" }, - "time": "2026-05-30T09:12:26+00:00" + "time": "2026-06-13T19:45:53+00:00" }, { "name": "tecnickcom/tc-lib-barcode", @@ -19493,21 +19565,21 @@ }, { "name": "phpstan/phpstan-doctrine", - "version": "2.0.25", + "version": "2.0.27", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "e20e8bf3223ae6eba9c4b5987c391d922e094b3c" + "reference": "39b4ca45a07cdd6366eeefa2f7a993cddf3b9f9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/e20e8bf3223ae6eba9c4b5987c391d922e094b3c", - "reference": "e20e8bf3223ae6eba9c4b5987c391d922e094b3c", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/39b4ca45a07cdd6366eeefa2f7a993cddf3b9f9f", + "reference": "39b4ca45a07cdd6366eeefa2f7a993cddf3b9f9f", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.1.34" + "phpstan/phpstan": "^2.2.2" }, "conflict": { "doctrine/collections": "<1.0", @@ -19564,9 +19636,9 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.25" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.27" }, - "time": "2026-06-02T20:27:36+00:00" + "time": "2026-06-10T10:39:35+00:00" }, { "name": "phpstan/phpstan-strict-rules", @@ -20216,12 +20288,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "b000295a5fd02609ee7ad31d084cfa904af8a69a" + "reference": "810e1d8cfbc718df8dacf74b62b7b9a1780b9698" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/b000295a5fd02609ee7ad31d084cfa904af8a69a", - "reference": "b000295a5fd02609ee7ad31d084cfa904af8a69a", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/810e1d8cfbc718df8dacf74b62b7b9a1780b9698", + "reference": "810e1d8cfbc718df8dacf74b62b7b9a1780b9698", "shasum": "" }, "conflict": { @@ -20346,7 +20418,7 @@ "code16/sharp": "<9.22", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<3.1.10", - "codeigniter4/framework": "<4.6.2", + "codeigniter4/framework": "<4.7.2", "codeigniter4/shield": "<1.0.0.0-beta8", "codiad/codiad": "<=2.8.4", "codingms/additional-tca": ">=1.7,<1.15.17|>=1.16,<1.16.9", @@ -20497,10 +20569,10 @@ "feehi/cms": "<=2.1.1", "feehi/feehicms": "<=2.1.1", "fenom/fenom": "<=2.12.1", - "filament/actions": ">=3.2,<3.2.123", + "filament/actions": ">=3.2,<3.2.123|>=4,<=4.11.3|>=5,<=5.6.3", "filament/filament": ">=4,<4.3.1", "filament/infolists": ">=3,<3.2.115", - "filament/tables": ">=3,<3.2.115|>=4,<4.8.5|>=5,<5.3.5", + "filament/tables": ">=3,<=3.3.50|>=4,<4.8.5|>=5,<5.3.5", "filegator/filegator": "<7.8", "filp/whoops": "<2.1.13", "fineuploader/php-traditional-server": "<=1.2.2", @@ -20564,11 +20636,12 @@ "gp247/core": "<1.1.24", "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<6.1.17|>=6.4.23,<=6.5", + "grumpydictator/firefly-iii": "<=6.6.2", "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", + "guzzlehttp/guzzle-services": "<1.5.4", "guzzlehttp/oauth-subscriber": "<0.8.1", - "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", + "guzzlehttp/psr7": "<2.10.2", "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "handcraftedinthealps/goodby-csv": "<1.4.3", "harvesthq/chosen": "<1.8.7", @@ -20611,7 +20684,7 @@ "inter-mediator/inter-mediator": "==5.5", "intercom/intercom-php": "==5.0.2", "invoiceninja/invoiceninja": "<5.13.4", - "ipl/web": "<=0.13", + "ipl/web": "<=0.10.2|>=0.11,<=0.13", "islandora/crayfish": "<4.1", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", @@ -20839,6 +20912,7 @@ "personnummer/personnummer": "<3.0.2", "ph7software/ph7builder": "<=17.9.1", "phanan/koel": "<=9.3.4", + "pheditor/pheditor": ">=2.0.1,<=2.0.3", "phenx/php-svg-lib": "<0.5.2", "php-censor/php-censor": "<2.0.13|>=2.1,<2.1.5", "php-mod/curl": "<2.3.2", @@ -20852,7 +20926,7 @@ "phpoffice/common": "<0.2.9", "phpoffice/math": "<=0.2", "phpoffice/phpexcel": "<=1.8.2", - "phpoffice/phpspreadsheet": "<=1.30.3|>=2,<=2.1.15|>=2.2,<=2.4.4|>=3,<=3.10.4|>=4,<=5.6", + "phpoffice/phpspreadsheet": "<=1.30.4|>=2,<=2.1.15|>=2.2,<=2.4.4|>=3,<=3.10.4|>=4,<=5.6", "phppgadmin/phppgadmin": "<=7.13", "phpseclib/phpseclib": "<=2.0.53|>=3,<=3.0.51", "phpservermon/phpservermon": "<3.6", @@ -20878,6 +20952,7 @@ "pocketmine/bedrock-protocol": "<8.0.2", "pocketmine/pocketmine-mp": "<5.42.1", "pocketmine/raklib": ">=0.14,<0.14.6|>=0.15,<0.15.1", + "poweradmin/poweradmin": "<4.2.4|>=4.3,<4.3.3", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockreassurance": "<=5.1.3", @@ -20947,7 +21022,7 @@ "shopware/core": "<6.6.10.18-dev|>=6.7,<6.7.10.1-dev", "shopware/platform": "<6.6.10.18-dev|>=6.7,<6.7.10.1-dev", "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", + "shopware/shopware": "<=6.3.5.2|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", "shopxo/shopxo": "<=6.4", "showdoc/showdoc": "<3.8.1", @@ -21118,22 +21193,23 @@ "twig/twig": "<3.27", "typicms/core": "<16.1.7", "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1|==14.2", + "typo3/cms-backend": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-beuser": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/cms-core": "<=8.7.56|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-core": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", "typo3/cms-dashboard": ">=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-felogin": ">=4.2,<4.2.3", + "typo3/cms-filelist": ">=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", - "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-form": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", - "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<13.4.31|>=14,<14.3.3", "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", "typo3/cms-lowlevel": ">=11,<=11.5.41", "typo3/cms-recordlist": ">=11,<11.5.48", - "typo3/cms-recycler": ">=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", + "typo3/cms-recycler": "<10.4.57|>=11,<11.5.51|>=12,<12.4.46|>=13,<13.4.31|>=14,<14.3.3", "typo3/cms-redirects": ">=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", "typo3/cms-scheduler": ">=11,<=11.5.41", @@ -21141,7 +21217,7 @@ "typo3/cms-webhooks": ">=12,<=12.4.30|>=13,<=13.4.11", "typo3/cms-workspaces": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": ">=1,<=1.5.2|>=2,<=2.1.3", + "typo3/html-sanitizer": "<2.3.2", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", @@ -21300,7 +21376,7 @@ "type": "tidelift" } ], - "time": "2026-06-05T20:39:10+00:00" + "time": "2026-06-12T20:48:39+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml index 387d71ad..17f8f4c2 100644 --- a/config/packages/monolog.yaml +++ b/config/packages/monolog.yaml @@ -51,6 +51,7 @@ when@prod: type: stream channels: [deprecation] path: "%kernel.logs_dir%/%kernel.environment%_deprecations.log" + level: "%env(DEPRECATION_LOG_LEVEL)%" when@docker: monolog: @@ -75,3 +76,4 @@ when@docker: type: stream channels: [deprecation] path: "%kernel.logs_dir%/%kernel.environment%_deprecations.log" + level: "%env(DEPRECATION_LOG_LEVEL)%" diff --git a/config/reference.php b/config/reference.php index 49c16f65..71b08412 100644 --- a/config/reference.php +++ b/config/reference.php @@ -653,7 +653,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param; * time_based_uuid_node?: scalar|Param|null, * }, * html_sanitizer?: bool|array{ // HtmlSanitizer configuration - * enabled?: bool|Param, // Default: false + * enabled?: bool|Param, // Default: true * sanitizers?: array_deprecations.log` file. This option sets the minimum log + level a deprecation notice must have to be written there. Since deprecation notices are logged with level `info`, + the default value of `emergency` effectively disables this dedicated deprecation log. Set it to `debug` to enable it. ## Banner diff --git a/public/kicad/footprints.txt b/public/kicad/footprints.txt index 5f691a41..a0b41279 100644 --- a/public/kicad/footprints.txt +++ b/public/kicad/footprints.txt @@ -1,4 +1,4 @@ -# Generated on Mon Jun 1 07:07:44 UTC 2026 +# Generated on Mon Jun 15 07:28:00 UTC 2026 # This file contains all footprints available in the offical KiCAD library Audio_Module:Reverb_BTDR-1H Audio_Module:Reverb_BTDR-1V @@ -12012,7 +12012,6 @@ Package_DFN_QFN:WDFN-8-1EP_4x3mm_P0.65mm_EP2.4x1.8mm_ThermalVias Package_DFN_QFN:WDFN-8-1EP_6x5mm_P1.27mm_EP3.4x4mm Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm_ThermalVias -Package_DFN_QFN:WDFN-8_2x2mm_P0.5mm Package_DFN_QFN:WFDFPN-8-1EP_3x2mm_P0.5mm_EP1.25x1.35mm Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm_ThermalVias @@ -12358,7 +12357,6 @@ Package_DirectFET:DirectFET_SQ Package_DirectFET:DirectFET_ST Package_LCC:Analog_LCC-8_5x5mm_P1.27mm Package_LCC:MO047AD_PLCC-52_19.1x19.1mm_P1.27mm -Package_LCC:PLCC-20 Package_LCC:PLCC-20_9.0x9.0mm_P1.27mm Package_LCC:PLCC-20_SMD-Socket Package_LCC:PLCC-20_THT-Socket diff --git a/public/kicad/symbols.txt b/public/kicad/symbols.txt index 7b4fde9c..b07fbf28 100644 --- a/public/kicad/symbols.txt +++ b/public/kicad/symbols.txt @@ -1,4 +1,4 @@ -# Generated on Mon Jun 1 07:08:24 UTC 2026 +# Generated on Mon Jun 15 07:28:38 UTC 2026 # This file contains all symbols available in the offical KiCAD library 4xxx:14528 4xxx:14529 @@ -5300,21 +5300,39 @@ Converter_DCDC:TMR-4812 Converter_DCDC:TMR-4821 Converter_DCDC:TMR-4822 Converter_DCDC:TMR-4823 +Converter_DCDC:TMR10-1211WI +Converter_DCDC:TMR10-1212WI +Converter_DCDC:TMR10-1213WI +Converter_DCDC:TMR10-1215WI +Converter_DCDC:TMR10-1222WI +Converter_DCDC:TMR10-1223WI Converter_DCDC:TMR10-2410WIR +Converter_DCDC:TMR10-2411WI Converter_DCDC:TMR10-2411WIR +Converter_DCDC:TMR10-2412WI Converter_DCDC:TMR10-2412WIR +Converter_DCDC:TMR10-2413WI Converter_DCDC:TMR10-2413WIR +Converter_DCDC:TMR10-2415WI Converter_DCDC:TMR10-2415WIR Converter_DCDC:TMR10-2421WIR +Converter_DCDC:TMR10-2422WI Converter_DCDC:TMR10-2422WIR +Converter_DCDC:TMR10-2423WI Converter_DCDC:TMR10-2423WIR Converter_DCDC:TMR10-4810WIR +Converter_DCDC:TMR10-4811WI Converter_DCDC:TMR10-4811WIR +Converter_DCDC:TMR10-4812WI Converter_DCDC:TMR10-4812WIR +Converter_DCDC:TMR10-4813WI Converter_DCDC:TMR10-4813WIR +Converter_DCDC:TMR10-4815WI Converter_DCDC:TMR10-4815WIR Converter_DCDC:TMR10-4821WIR +Converter_DCDC:TMR10-4822WI Converter_DCDC:TMR10-4822WIR +Converter_DCDC:TMR10-4823WI Converter_DCDC:TMR10-4823WIR Converter_DCDC:TMR10-7210WIR Converter_DCDC:TMR10-7211WIR @@ -14593,6 +14611,8 @@ MCU_Texas:LM4F111C4QR MCU_Texas:LM4F111E5QR MCU_Texas:LM4F111H5QR MCU_Texas:MSP432E401Y +MCU_Texas:MSPM0C110xSDDF +MCU_Texas:MSPM0C110xSDSG MCU_Texas:TM4C1230C3PM MCU_Texas:TM4C1230D5PM MCU_Texas:TM4C1230E6PM @@ -15115,6 +15135,7 @@ Memory_Flash:AM29F400Bx-xxEx Memory_Flash:AM29F400Bx-xxSx Memory_Flash:AM29PDL128G Memory_Flash:AT25DF041x-UxN-x +Memory_Flash:AT25SF041B-SSHD-X Memory_Flash:AT25SF081-SSHD-X Memory_Flash:AT25SF081-SSHF-X Memory_Flash:AT25SF081-XMHD-X @@ -15670,6 +15691,7 @@ Power_Management:LM5069MM-1 Power_Management:LM5069MM-2 Power_Management:LM66100DCK Power_Management:LM74700 +Power_Management:LM74701-Q1 Power_Management:LMG3410 Power_Management:LMG5200 Power_Management:LT1641-1 @@ -15771,6 +15793,7 @@ Power_Management:TPS22810DBV Power_Management:TPS22810DRV Power_Management:TPS22917DBV Power_Management:TPS22917LDBV +Power_Management:TPS22919DCK Power_Management:TPS22929D Power_Management:TPS22993 Power_Management:TPS2412D @@ -16480,6 +16503,7 @@ RF_Module:DWM3000 RF_Module:E18-MS1-PCB RF_Module:E73-2G4M04S-52810 RF_Module:E73-2G4M04S-52832 +RF_Module:ESP-01 RF_Module:ESP-07 RF_Module:ESP-12E RF_Module:ESP-12F @@ -16681,6 +16705,19 @@ Reference_Voltage:LM4040LP-4.1 Reference_Voltage:LM4040LP-5 Reference_Voltage:LM4040LP-8.2 Reference_Voltage:LM4041LP-ADJ +Reference_Voltage:LM4050xEM3-2.1 +Reference_Voltage:LM4050xEM3-2.5 +Reference_Voltage:LM4050xEM3-3.0 +Reference_Voltage:LM4050xEM3-3.3 +Reference_Voltage:LM4050xEM3-4.1 +Reference_Voltage:LM4050xEM3-5.0 +Reference_Voltage:LM4050xEX3-2.1 +Reference_Voltage:LM4050xEX3-2.5 +Reference_Voltage:LM4050xEX3-3.3 +Reference_Voltage:LM4050xEX3-4.1 +Reference_Voltage:LM4050xEX3-5.0 +Reference_Voltage:LM4051xEM3-1.2 +Reference_Voltage:LM4051xEX3-1.2 Reference_Voltage:LM4125AIM5-2.5 Reference_Voltage:LM4125IM5-2.0 Reference_Voltage:LM4125IM5-2.5 @@ -16828,7 +16865,6 @@ Reference_Voltage:MCP1501-25xCH Reference_Voltage:MCP1501-25xRW Reference_Voltage:MCP1501-25xSN Reference_Voltage:MCP1501-30xCH -Reference_Voltage:MCP1501-30xRW Reference_Voltage:MCP1501-30xSN Reference_Voltage:MCP1501-33xCH Reference_Voltage:MCP1501-33xRW @@ -20989,6 +21025,7 @@ Sensor_Temperature:MCP9501 Sensor_Temperature:MCP9502 Sensor_Temperature:MCP9503 Sensor_Temperature:MCP9504 +Sensor_Temperature:MCP96xx01x-x-MX Sensor_Temperature:MCP9700Ax-ELT Sensor_Temperature:MCP9700Ax-ETT Sensor_Temperature:MCP9700Ax-HLT diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php index 71f8ba5c..b8c50d9b 100644 --- a/src/Controller/TreeController.php +++ b/src/Controller/TreeController.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\Controller; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\HttpFoundation\Response; use App\Entity\ProjectSystem\Project; use App\Entity\Parts\Category; @@ -55,7 +56,7 @@ class TreeController extends AbstractController #[Route(path: '/category/{id}', name: 'tree_category')] #[Route(path: '/categories', name: 'tree_category_root')] - public function categoryTree(?Category $category = null): JsonResponse + public function categoryTree(#[MapEntity(id: 'id')] ?Category $category = null): JsonResponse { if ($this->isGranted('@parts.read') && $this->isGranted('@categories.read')) { $tree = $this->treeGenerator->getTreeView(Category::class, $category, 'list_parts_root'); @@ -68,7 +69,7 @@ class TreeController extends AbstractController #[Route(path: '/footprint/{id}', name: 'tree_footprint')] #[Route(path: '/footprints', name: 'tree_footprint_root')] - public function footprintTree(?Footprint $footprint = null): JsonResponse + public function footprintTree(#[MapEntity(id: 'id')] ?Footprint $footprint = null): JsonResponse { if ($this->isGranted('@parts.read') && $this->isGranted('@footprints.read')) { $tree = $this->treeGenerator->getTreeView(Footprint::class, $footprint, 'list_parts_root'); @@ -80,7 +81,7 @@ class TreeController extends AbstractController #[Route(path: '/location/{id}', name: 'tree_location')] #[Route(path: '/locations', name: 'tree_location_root')] - public function locationTree(?StorageLocation $location = null): JsonResponse + public function locationTree(#[MapEntity(id: 'id')] ?StorageLocation $location = null): JsonResponse { if ($this->isGranted('@parts.read') && $this->isGranted('@storelocations.read')) { $tree = $this->treeGenerator->getTreeView(StorageLocation::class, $location, 'list_parts_root'); @@ -93,7 +94,7 @@ class TreeController extends AbstractController #[Route(path: '/manufacturer/{id}', name: 'tree_manufacturer')] #[Route(path: '/manufacturers', name: 'tree_manufacturer_root')] - public function manufacturerTree(?Manufacturer $manufacturer = null): JsonResponse + public function manufacturerTree(#[MapEntity(id: 'id')] ?Manufacturer $manufacturer = null): JsonResponse { if ($this->isGranted('@parts.read') && $this->isGranted('@manufacturers.read')) { $tree = $this->treeGenerator->getTreeView(Manufacturer::class, $manufacturer, 'list_parts_root'); @@ -106,7 +107,7 @@ class TreeController extends AbstractController #[Route(path: '/supplier/{id}', name: 'tree_supplier')] #[Route(path: '/suppliers', name: 'tree_supplier_root')] - public function supplierTree(?Supplier $supplier = null): JsonResponse + public function supplierTree(#[MapEntity(id: 'id')] ?Supplier $supplier = null): JsonResponse { if ($this->isGranted('@parts.read') && $this->isGranted('@suppliers.read')) { $tree = $this->treeGenerator->getTreeView(Supplier::class, $supplier, 'list_parts_root'); @@ -119,7 +120,7 @@ class TreeController extends AbstractController #[Route(path: '/device/{id}', name: 'tree_device')] #[Route(path: '/devices', name: 'tree_device_root')] - public function deviceTree(?Project $device = null): JsonResponse + public function deviceTree(#[MapEntity(id: 'id')] ?Project $device = null): JsonResponse { if ($this->isGranted('@projects.read')) { $tree = $this->treeGenerator->getTreeView(Project::class, $device, 'devices'); diff --git a/src/DataTables/AttachmentDataTable.php b/src/DataTables/AttachmentDataTable.php index 16e6a7a7..6c4c905a 100644 --- a/src/DataTables/AttachmentDataTable.php +++ b/src/DataTables/AttachmentDataTable.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\DataTables; +use App\DataTables\Column\HTMLColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\PrettyBoolColumn; use App\DataTables\Column\RowClassColumn; @@ -40,14 +41,19 @@ use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableTypeInterface; use Symfony\Contracts\Translation\TranslatorInterface; -final class AttachmentDataTable implements DataTableTypeInterface +final readonly class AttachmentDataTable implements DataTableTypeInterface { - public function __construct(private readonly TranslatorInterface $translator, private readonly EntityURLGenerator $entityURLGenerator, private readonly AttachmentManager $attachmentHelper, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly ElementTypeNameGenerator $elementTypeNameGenerator) + public function __construct(private TranslatorInterface $translator, private EntityURLGenerator $entityURLGenerator, private AttachmentManager $attachmentHelper, private AttachmentURLGenerator $attachmentURLGenerator, private ElementTypeNameGenerator $elementTypeNameGenerator) { } public function configure(DataTable $dataTable, array $options): void { + /************************************************************************************************************* + * Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the + * HTMLColumn, if necessary + ************************************************************************************************************/ + $dataTable->add('dont_matter', RowClassColumn::class, [ 'render' => function ($value, Attachment $context): string { //Mark attachments yellow which have an internal file linked that doesn't exist @@ -59,10 +65,10 @@ final class AttachmentDataTable implements DataTableTypeInterface }, ]); - $dataTable->add('picture', TextColumn::class, [ + $dataTable->add('picture', HTMLColumn::class, [ 'label' => '', 'className' => 'no-colvis', - 'render' => function ($value, Attachment $context): string { + 'data' => function (Attachment $context): string { if ($context->isPicture() && $this->attachmentHelper->isInternalFileExisting($context)) { @@ -95,65 +101,65 @@ final class AttachmentDataTable implements DataTableTypeInterface 'orderField' => 'NATSORT(attachment.name)', ]); - $dataTable->add('attachment_type', TextColumn::class, [ + $dataTable->add('attachment_type', HTMLColumn::class, [ 'label' => 'attachment.table.type', 'field' => 'attachment_type.name', 'orderField' => 'NATSORT(attachment_type.name)', - 'render' => fn($value, Attachment $context): string => sprintf( + 'data' => fn(Attachment $context, $value): string => sprintf( '%s', $this->entityURLGenerator->editURL($context->getAttachmentType()), htmlspecialchars((string) $value) ), ]); - $dataTable->add('element', TextColumn::class, [ + $dataTable->add('element', HTMLColumn::class, [ 'label' => 'attachment.table.element', //'propertyPath' => 'element.name', - 'render' => fn($value, Attachment $context): string => sprintf( + 'data' => fn(Attachment $context): string => sprintf( '%s', $this->entityURLGenerator->infoURL($context->getElement()), $this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true) ), ]); - $dataTable->add('internal_link', TextColumn::class, [ + $dataTable->add('internal_link', HTMLColumn::class, [ 'label' => 'attachment.table.internal_file', 'propertyPath' => 'filename', 'orderField' => 'NATSORT(attachment.original_filename)', - 'render' => function ($value, Attachment $context) { + 'data' => function (Attachment $context, $value) { if ($this->attachmentHelper->isInternalFileExisting($context)) { return sprintf( '%s', $this->entityURLGenerator->viewURL($context), - htmlspecialchars($value) + htmlspecialchars((string) $value) ); } - return $value; - } + return htmlspecialchars((string) $value); + }, ]); - $dataTable->add('external_link', TextColumn::class, [ + $dataTable->add('external_link', HTMLColumn::class, [ 'label' => 'attachment.table.external_link', 'propertyPath' => 'host', 'orderField' => 'attachment.external_path', - 'render' => function ($value, Attachment $context) { + 'data' => function (Attachment $context, $value) { if ($context->hasExternal()) { return sprintf( '%s', htmlspecialchars((string) $context->getExternalPath()), htmlspecialchars((string) $context->getExternalPath()), - htmlspecialchars($value), + htmlspecialchars((string) $value), ); } - return $value; - } + return htmlspecialchars((string) $value); + }, ]); - $dataTable->add('filesize', TextColumn::class, [ + $dataTable->add('filesize', HTMLColumn::class, [ 'label' => $this->translator->trans('attachment.table.filesize'), - 'render' => function ($value, Attachment $context) { + 'data' => function (Attachment $context) { if (!$context->hasInternal()) { return sprintf( ' @@ -168,7 +174,7 @@ final class AttachmentDataTable implements DataTableTypeInterface ' %s ', - $this->attachmentHelper->getHumanFileSize($context) + htmlspecialchars($this->attachmentHelper->getHumanFileSize($context)) ); } diff --git a/src/DataTables/Column/EntityColumn.php b/src/DataTables/Column/EntityColumn.php index 54ae3fb3..b5d71a08 100644 --- a/src/DataTables/Column/EntityColumn.php +++ b/src/DataTables/Column/EntityColumn.php @@ -78,7 +78,7 @@ class EntityColumn extends AbstractColumn ); } - return sprintf('%s', $value); + return sprintf('%s', htmlspecialchars($value)); } return ''; diff --git a/src/DataTables/Column/HTMLColumn.php b/src/DataTables/Column/HTMLColumn.php new file mode 100644 index 00000000..a1220dd3 --- /dev/null +++ b/src/DataTables/Column/HTMLColumn.php @@ -0,0 +1,37 @@ +. + */ +namespace App\DataTables\Column; + +use Omines\DataTablesBundle\Column\TextColumn; + +/** + * A TextColumn whose value is always treated as raw HTML and therefore never passed through htmlspecialchars(). + * The value returned by the 'data' option must already contain properly escaped/sanitized HTML, as it is output as-is. + */ +class HTMLColumn extends TextColumn +{ + public function isRaw(): bool + { + return true; + } +} diff --git a/src/DataTables/Column/IconLinkColumn.php b/src/DataTables/Column/IconLinkColumn.php index 6704cb4a..47b35d82 100644 --- a/src/DataTables/Column/IconLinkColumn.php +++ b/src/DataTables/Column/IconLinkColumn.php @@ -87,9 +87,9 @@ class IconLinkColumn extends AbstractColumn return sprintf( '', $disabled ? 'disabled' : '', - $href, - $title, - $icon + htmlspecialchars($href), + htmlspecialchars($title ?? ''), + htmlspecialchars($icon ?? '') ); } diff --git a/src/DataTables/ErrorDataTable.php b/src/DataTables/ErrorDataTable.php index 833ea934..a16b453e 100644 --- a/src/DataTables/ErrorDataTable.php +++ b/src/DataTables/ErrorDataTable.php @@ -22,9 +22,9 @@ declare(strict_types=1); */ namespace App\DataTables; +use App\DataTables\Column\HTMLColumn; use App\DataTables\Column\RowClassColumn; use Omines\DataTablesBundle\Adapter\ArrayAdapter; -use Omines\DataTablesBundle\Column\TextColumn; use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableFactory; use Omines\DataTablesBundle\DataTableTypeInterface; @@ -32,7 +32,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\OptionsResolver\OptionsResolver; -class ErrorDataTable implements DataTableTypeInterface +final readonly class ErrorDataTable implements DataTableTypeInterface { public function configureOptions(OptionsResolver $optionsResolver): void { @@ -49,6 +49,11 @@ class ErrorDataTable implements DataTableTypeInterface public function configure(DataTable $dataTable, array $options): void { + /************************************************************************************************************* + * Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the + * HTMLColumn, if necessary + ************************************************************************************************************/ + $optionsResolver = new OptionsResolver(); $this->configureOptions($optionsResolver); $options = $optionsResolver->resolve($options); @@ -58,9 +63,9 @@ class ErrorDataTable implements DataTableTypeInterface 'render' => fn($value, $context): string => 'table-warning', ]) - ->add('error', TextColumn::class, [ + ->add('error', HTMLColumn::class, [ 'label' => 'error_table.error', - 'render' => fn($value, $context): string => ' ' . $value, + 'data' => fn($context, $value): string => ' ' . htmlspecialchars((string) $value), ]) ; diff --git a/src/DataTables/Helpers/PartDataTableHelper.php b/src/DataTables/Helpers/PartDataTableHelper.php index 54094ff1..2f40dbd2 100644 --- a/src/DataTables/Helpers/PartDataTableHelper.php +++ b/src/DataTables/Helpers/PartDataTableHelper.php @@ -62,7 +62,7 @@ class PartDataTableHelper } if ($context->getBuiltProject() instanceof Project) { $icon = sprintf('', - $this->translator->trans('part.info.projectBuildPart.hint').': '.$context->getBuiltProject()->getName()); + $this->translator->trans('part.info.projectBuildPart.hint').': '.htmlspecialchars($context->getBuiltProject()->getName())); } diff --git a/src/DataTables/LogDataTable.php b/src/DataTables/LogDataTable.php index 2c37767b..5c4ca88b 100644 --- a/src/DataTables/LogDataTable.php +++ b/src/DataTables/LogDataTable.php @@ -25,6 +25,7 @@ namespace App\DataTables; use App\DataTables\Column\EnumColumn; use App\Entity\LogSystem\LogTargetType; use Symfony\Bundle\SecurityBundle\Security; +use App\DataTables\Column\HTMLColumn; use App\DataTables\Column\IconLinkColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\LogEntryExtraColumn; @@ -59,7 +60,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\Translation\TranslatorInterface; -class LogDataTable implements DataTableTypeInterface +final readonly class LogDataTable implements DataTableTypeInterface { protected LogEntryRepository $logRepo; @@ -95,6 +96,11 @@ class LogDataTable implements DataTableTypeInterface public function configure(DataTable $dataTable, array $options): void { + /************************************************************************************************************* + * Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the + * HTMLColumn, if necessary + ************************************************************************************************************/ + $resolver = new OptionsResolver(); $this->configureOptions($resolver); $options = $resolver->resolve($options); @@ -104,10 +110,10 @@ class LogDataTable implements DataTableTypeInterface 'render' => fn($value, AbstractLogEntry $context) => $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString()), ]); - $dataTable->add('symbol', TextColumn::class, [ + $dataTable->add('symbol', HTMLColumn::class, [ 'label' => '', 'className' => 'no-colvis', - 'render' => fn($value, AbstractLogEntry $context): string => sprintf( + 'data' => fn(AbstractLogEntry $context): string => sprintf( '', $this->logLevelHelper->logLevelToIconClass($context->getLevelString()), $context->getLevelString() @@ -128,10 +134,10 @@ class LogDataTable implements DataTableTypeInterface ) ]); - $dataTable->add('type', TextColumn::class, [ + $dataTable->add('type', HTMLColumn::class, [ 'label' => 'log.type', 'propertyPath' => 'type', - 'render' => function (string $value, AbstractLogEntry $context) { + 'data' => function (AbstractLogEntry $context, string $value) { $text = $this->translator->trans('log.type.'.$value); if ($context instanceof PartStockChangedLogEntry) { @@ -149,20 +155,20 @@ class LogDataTable implements DataTableTypeInterface 'label' => 'log.level', 'visible' => 'system_log' === $options['mode'], 'propertyPath' => 'levelString', - 'render' => fn(string $value, AbstractLogEntry $context) => $this->translator->trans('log.level.'.$value), + 'data' => fn(AbstractLogEntry $context, string $value) => $this->translator->trans('log.level.'.$value), ]); - $dataTable->add('user', TextColumn::class, [ + $dataTable->add('user', HTMLColumn::class, [ 'label' => 'log.user', 'orderField' => 'NATSORT(user.name)', - 'render' => function ($value, AbstractLogEntry $context): string { + 'data' => function (AbstractLogEntry $context): string { $user = $context->getUser(); //If user was deleted, show the info from the username field if (!$user instanceof User) { if ($context->isCLIEntry()) { return sprintf('%s [%s]', - htmlentities((string) $context->getCLIUsername()), + htmlspecialchars((string) $context->getCLIUsername()), $this->translator->trans('log.cli_user') ); } @@ -170,7 +176,7 @@ class LogDataTable implements DataTableTypeInterface //Else we just deal with a deleted user return sprintf( '@%s [%s]', - htmlentities($context->getUsername()), + htmlspecialchars($context->getUsername()), $this->translator->trans('log.target_deleted'), ); } @@ -182,7 +188,7 @@ class LogDataTable implements DataTableTypeInterface $img_url, $this->userAvatarHelper->getAvatarMdURL($user), $this->urlGenerator->generate('user_info', ['id' => $user->getID()]), - htmlentities($user->getFullName(true)) + htmlspecialchars($user->getFullName(true)) ); }, ]); @@ -194,7 +200,7 @@ class LogDataTable implements DataTableTypeInterface 'render' => function (LogTargetType $value, AbstractLogEntry $context) { $class = $value->toClass(); if (null !== $class) { - return $this->elementTypeNameGenerator->getLocalizedTypeLabel($class); + return $this->elementTypeNameGenerator->typeLabel($class); } return ''; @@ -216,9 +222,9 @@ class LogDataTable implements DataTableTypeInterface 'icon' => 'fas fa-fw fa-eye', 'href' => function ($value, AbstractLogEntry $context) { if ( + $context instanceof CollectionElementDeleted || ($context instanceof TimeTravelInterface && $context->hasOldDataInformation()) - || $context instanceof CollectionElementDeleted ) { try { $target = $this->logRepo->getTargetElement($context); diff --git a/src/DataTables/PartsDataTable.php b/src/DataTables/PartsDataTable.php index bcf64056..5912a20e 100644 --- a/src/DataTables/PartsDataTable.php +++ b/src/DataTables/PartsDataTable.php @@ -25,6 +25,7 @@ namespace App\DataTables; use App\DataTables\Adapters\TwoStepORMAdapter; use App\DataTables\Column\EntityColumn; use App\DataTables\Column\EnumColumn; +use App\DataTables\Column\HTMLColumn; use App\DataTables\Column\IconLinkColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\MarkdownColumn; @@ -58,7 +59,7 @@ use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\Translation\TranslatorInterface; -final class PartsDataTable implements DataTableTypeInterface +final readonly class PartsDataTable implements DataTableTypeInterface { public const LENGTH_MENU = [[10, 25, 50, 100, 250, 500, -1], [10, 25, 50, 100, 250, 500, "All"]]; @@ -94,6 +95,11 @@ final class PartsDataTable implements DataTableTypeInterface * When adding columns here, add them also to PartTableColumns enum, to make them configurable in the settings! *************************************************************************************************************/ + /************************************************************************************************************* + * Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the + * HTMLColumn, if necessary + ************************************************************************************************************/ + $this->csh //Color the table rows depending on the review and favorite status ->add('row_color', RowClassColumn::class, [ @@ -109,23 +115,23 @@ final class PartsDataTable implements DataTableTypeInterface }, ], visibility_configurable: false) ->add('select', SelectColumn::class, visibility_configurable: false) - ->add('picture', TextColumn::class, [ + ->add('picture', HTMLColumn::class, [ 'label' => '', 'className' => 'no-colvis', - 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderPicture($context), + 'data' => fn(Part $context) => $this->partDataTableHelper->renderPicture($context), ], visibility_configurable: false) - ->add('name', TextColumn::class, [ + ->add('name', HTMLColumn::class, [ 'label' => $this->translator->trans('part.table.name'), - 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderName($context), + 'data' => fn(Part $context) => $this->partDataTableHelper->renderName($context), 'orderField' => 'NATSORT(part.name)' ]) ->add('si_value', TextColumn::class, [ 'label' => $this->translator->trans('part.table.si_value'), - 'render' => function ($value, Part $context): string { + 'data' => function (Part $context): string { $siValue = SiValueSort::sqliteSiValue($context->getName()); if ($siValue !== null) { //Output it as scientific number with a big E - return htmlspecialchars(sprintf('%G', $siValue)); + return sprintf('%G', $siValue); } return ''; }, @@ -156,38 +162,38 @@ final class PartsDataTable implements DataTableTypeInterface 'label' => $this->translator->trans('part.table.manufacturer'), 'orderField' => 'NATSORT(_manufacturer.name)' ]) - ->add('storelocation', TextColumn::class, [ + ->add('storelocation', HTMLColumn::class, [ 'label' => $this->translator->trans('part.table.storeLocations'), //We need to use a aggregate function to get the first store location, as we have a one-to-many relation 'orderField' => 'NATSORT(MIN(_storelocations.name))', - 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderStorageLocations($context), + 'data' => fn(Part $context) => $this->partDataTableHelper->renderStorageLocations($context), ], alias: 'storage_location') - ->add('amount', TextColumn::class, [ + ->add('amount', HTMLColumn::class, [ 'label' => $this->translator->trans('part.table.amount'), - 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderAmount($context), + 'data' => fn(Part $context) => $this->partDataTableHelper->renderAmount($context), 'orderField' => 'amountSum' ]) ->add('minamount', TextColumn::class, [ 'label' => $this->translator->trans('part.table.minamount'), - 'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format( + 'data' => fn(Part $context, $value): string => $this->amountFormatter->format( $value, $context->getPartUnit() - )), + ), ]) ->add('partUnit', TextColumn::class, [ 'label' => $this->translator->trans('part.table.partUnit'), 'orderField' => 'NATSORT(_partUnit.name)', - 'render' => function ($value, Part $context): string { + 'data' => function (Part $context): string { $partUnit = $context->getPartUnit(); if ($partUnit === null) { return ''; } - $tmp = htmlspecialchars($partUnit->getName()); + $tmp = $partUnit->getName(); if ($partUnit->getUnit()) { - $tmp .= ' (' . htmlspecialchars($partUnit->getUnit()) . ')'; + $tmp .= ' (' . $partUnit->getUnit() . ')'; } return $tmp; } @@ -195,14 +201,14 @@ final class PartsDataTable implements DataTableTypeInterface ->add('partCustomState', TextColumn::class, [ 'label' => $this->translator->trans('part.table.partCustomState'), 'orderField' => 'NATSORT(_partCustomState.name)', - 'render' => function($value, Part $context): string { + 'data' => function(Part $context): string { $partCustomState = $context->getPartCustomState(); if ($partCustomState === null) { return ''; } - return htmlspecialchars($partCustomState->getName()); + return $partCustomState->getName(); } ]) ->add('addedDate', LocaleDateTimeColumn::class, [ @@ -248,25 +254,25 @@ final class PartsDataTable implements DataTableTypeInterface ]) ->add('eda_reference', TextColumn::class, [ 'label' => $this->translator->trans('part.table.eda_reference'), - 'render' => static fn($value, Part $context) => htmlspecialchars($context->getEdaInfo()->getReferencePrefix() ?? ''), + 'data' => static fn(Part $context) => $context->getEdaInfo()->getReferencePrefix() ?? '', 'orderField' => 'NATSORT(part.eda_info.reference_prefix)' ]) ->add('eda_value', TextColumn::class, [ 'label' => $this->translator->trans('part.table.eda_value'), - 'render' => static fn($value, Part $context) => htmlspecialchars($context->getEdaInfo()->getValue() ?? ''), + 'data' => static fn(Part $context) => $context->getEdaInfo()->getValue() ?? '', 'orderField' => 'NATSORT(part.eda_info.value)' ]) - ->add('eda_status', TextColumn::class, [ + ->add('eda_status', HTMLColumn::class, [ 'label' => $this->translator->trans('part.table.eda_status'), - 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderEdaStatus($context), + 'data' => fn(Part $context) => $this->partDataTableHelper->renderEdaStatus($context), 'className' => 'text-center', ]); //Add a column to list the projects where the part is used, when the user has the permission to see the projects if ($this->security->isGranted('read', Project::class)) { - $this->csh->add('projects', TextColumn::class, [ + $this->csh->add('projects', HTMLColumn::class, [ 'label' => $this->translator->trans('project.labelp'), - 'render' => function ($value, Part $context): string { + 'data' => function (Part $context): string { //Only show the first 5 projects names $projects = $context->getProjects(); $tmp = ""; @@ -286,7 +292,7 @@ final class PartsDataTable implements DataTableTypeInterface } return $tmp; - } + }, ]); } diff --git a/src/DataTables/ProjectBomEntriesDataTable.php b/src/DataTables/ProjectBomEntriesDataTable.php index b5beeca0..f65f0df7 100644 --- a/src/DataTables/ProjectBomEntriesDataTable.php +++ b/src/DataTables/ProjectBomEntriesDataTable.php @@ -25,6 +25,7 @@ namespace App\DataTables; use App\DataTables\Adapters\TwoStepORMAdapter; use App\DataTables\Column\EntityColumn; use App\DataTables\Column\EnumColumn; +use App\DataTables\Column\HTMLColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\MarkdownColumn; use App\DataTables\Helpers\PartDataTableHelper; @@ -48,7 +49,7 @@ use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableTypeInterface; use Symfony\Contracts\Translation\TranslatorInterface; -class ProjectBomEntriesDataTable implements DataTableTypeInterface +final readonly class ProjectBomEntriesDataTable implements DataTableTypeInterface { public function __construct( protected EntityURLGenerator $entityURLGenerator, @@ -63,17 +64,22 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface public function configure(DataTable $dataTable, array $options): void { + /************************************************************************************************************* + * Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the + * HTMLColumn, if necessary + ************************************************************************************************************/ + $dataTable //->add('select', SelectColumn::class) - ->add('picture', TextColumn::class, [ + ->add('picture', HTMLColumn::class, [ 'label' => '', 'className' => 'no-colvis', - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { if(!$context->getPart() instanceof Part) { return ''; } return $this->partDataTableHelper->renderPicture($context->getPart()); - } + }, ]) ->add('id', TextColumn::class, [ @@ -85,27 +91,27 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface 'label' => $this->translator->trans('project.bom.quantity'), 'className' => 'text-center', 'orderField' => 'bom_entry.quantity', - 'render' => function ($value, ProjectBOMEntry $context): float|string { + 'data' => function (ProjectBOMEntry $context): float|string { //If we have a non-part entry, only show the rounded quantity if (!$context->getPart() instanceof Part) { return round($context->getQuantity()); } //Otherwise use the unit of the part to format the quantity - return htmlspecialchars($this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit())); + return $this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit()); }, ]) ->add('partId', TextColumn::class, [ 'label' => $this->translator->trans('project.bom.part_id'), 'visible' => true, 'orderField' => 'part.id', - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { return $context->getPart() instanceof Part ? (string) $context->getPart()->getId() : ''; }, ]) - ->add('name', TextColumn::class, [ + ->add('name', HTMLColumn::class, [ 'label' => $this->translator->trans('part.table.name'), 'orderField' => 'NATSORT(part.name)', - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { if(!$context->getPart() instanceof Part) { return htmlspecialchars((string) $context->getName()); } @@ -123,11 +129,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface 'label' => $this->translator->trans('part.table.ipn'), 'orderField' => 'NATSORT(part.ipn)', 'visible' => false, - 'render' => function ($value, ProjectBOMEntry $context) { - if($context->getPart() instanceof Part) { - return $context->getPart()->getIpn(); - } - } + 'data' => fn (ProjectBOMEntry $context) => $context->getPart()?->getIpn() ]) ->add('description', MarkdownColumn::class, [ 'label' => $this->translator->trans('part.table.description'), @@ -172,9 +174,9 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface }, ]) - ->add('mountnames', TextColumn::class, [ + ->add('mountnames', HTMLColumn::class, [ 'label' => 'project.bom.mountnames', - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { $html = ''; foreach (explode(',', $context->getMountnames()) as $mountname) { @@ -184,34 +186,34 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface }, ]) - ->add('instockAmount', TextColumn::class, [ + ->add('instockAmount', HTMLColumn::class, [ 'label' => 'project.bom.instockAmount', 'visible' => false, - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { if ($context->getPart() !== null) { return $this->partDataTableHelper->renderAmount($context->getPart()); } return ''; - } + }, ]) - ->add('storelocation', TextColumn::class, [ + ->add('storelocation', HTMLColumn::class, [ 'label' => $this->translator->trans('part.table.storeLocations'), //We need to use a aggregate function to get the first store location, as we have a one-to-many relation 'orderField' => 'NATSORT(MIN(_storelocations.name))', 'visible' => false, - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { if ($context->getPart() !== null) { return $this->partDataTableHelper->renderStorageLocations($context->getPart()); } return ''; - } + }, ]) ->add('price', TextColumn::class, [ 'label' => 'project.bom.price', 'visible' => false, - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { $price = $this->projectBuildHelper->getEntryUnitPrice($context); return $this->moneyFormatter->format($price->toScale(2, RoundingMode::Up)->toFloat(), null, 2, true); }, @@ -219,7 +221,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface ->add('ext_price', TextColumn::class, [ 'label' => 'project.bom.ext_price', 'visible' => false, - 'render' => function ($value, ProjectBOMEntry $context) { + 'data' => function (ProjectBOMEntry $context) { $price = $this->projectBuildHelper->getEntryUnitPrice($context); return $this->moneyFormatter->format( $price->multipliedBy(BigDecimal::fromFloatShortest($context->getQuantity())) diff --git a/src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php b/src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php index d05b6b9c..b8e70ff2 100644 --- a/src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php +++ b/src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php @@ -35,8 +35,10 @@ class SetSQLModeMiddlewareDriver extends AbstractDriverMiddleware { //Only set this on MySQL connections, as other databases don't support this parameter if($params['driver'] === 'pdo_mysql') { - //1002 is \PDO::MYSQL_ATTR_INIT_COMMAND constant value - $params['driverOptions'][\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))'; + //PDO::MYSQL_ATTR_INIT_COMMAND is deprecated since PHP 8.5 in favor of Pdo\Mysql::ATTR_INIT_COMMAND, + //but the Pdo\Mysql class only exists since PHP 8.4. Both constants have the same value (1002). + $initCommandAttr = class_exists(\Pdo\Mysql::class) ? \Pdo\Mysql::ATTR_INIT_COMMAND : \PDO::MYSQL_ATTR_INIT_COMMAND; + $params['driverOptions'][$initCommandAttr] = 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))'; } return parent::connect($params); diff --git a/src/Entity/Parts/StorageLocation.php b/src/Entity/Parts/StorageLocation.php index 6c455ae5..7ba400d9 100644 --- a/src/Entity/Parts/StorageLocation.php +++ b/src/Entity/Parts/StorageLocation.php @@ -80,7 +80,7 @@ use Symfony\Component\Validator\Constraints as Assert; ) ], uriVariables: [ - 'id' => new Link(fromProperty: 'children', fromClass: Manufacturer::class) + 'id' => new Link(fromProperty: 'children', fromClass: StorageLocation::class) ], normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] )] diff --git a/src/Services/ImportExportSystem/BOMValidationService.php b/src/Services/ImportExportSystem/BOMValidationService.php index 74f81fe3..9f4cf5b8 100644 --- a/src/Services/ImportExportSystem/BOMValidationService.php +++ b/src/Services/ImportExportSystem/BOMValidationService.php @@ -29,13 +29,13 @@ use Symfony\Contracts\Translation\TranslatorInterface; /** * Service for validating BOM import data with comprehensive validation rules - * and user-friendly error messages. + * and user-friendly error messages. The results are not HTML safe, and must be escaped before display! */ -class BOMValidationService +readonly class BOMValidationService { public function __construct( - private readonly EntityManagerInterface $entityManager, - private readonly TranslatorInterface $translator + private EntityManagerInterface $entityManager, + private TranslatorInterface $translator ) { } @@ -473,4 +473,4 @@ class BOMValidationService : 0, ]; } -} \ No newline at end of file +} diff --git a/templates/log_system/details/log_details.html.twig b/templates/log_system/details/log_details.html.twig index aff127f4..2255dd97 100644 --- a/templates/log_system/details/log_details.html.twig +++ b/templates/log_system/details/log_details.html.twig @@ -58,7 +58,7 @@ {% trans %}log.target{% endtrans %} - {{ target_html|raw }} + {{ target_html|sanitize_html }} @@ -111,7 +111,7 @@ {% elseif log_entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted') %} {% include "log_system/details/_extra_collection_element_deleted.html.twig" %} {% else %} - {{ extra_html | raw }} + {{ extra_html | sanitize_html }} {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/projects/_bom_validation_results.html.twig b/templates/projects/_bom_validation_results.html.twig index 68f1b827..cb92e7bc 100644 --- a/templates/projects/_bom_validation_results.html.twig +++ b/templates/projects/_bom_validation_results.html.twig @@ -68,7 +68,7 @@

{% trans %}project.bom_import.validation.errors.description{% endtrans %}

    {% for error in validation_result.errors %} -
  • {{ error|raw }}
  • +
  • {{ error }}
  • {% endfor %}
@@ -80,7 +80,7 @@

{% trans %}project.bom_import.validation.warnings.description{% endtrans %}

    {% for warning in validation_result.warnings %} -
  • {{ warning|raw }}
  • +
  • {{ warning }}
  • {% endfor %}
@@ -91,7 +91,7 @@

{% trans %}project.bom_import.validation.info.title{% endtrans %}

    {% for info in validation_result.info %} -
  • {{ info|raw }}
  • +
  • {{ info }}
  • {% endfor %}
@@ -139,21 +139,21 @@ {% if line_result.errors is not empty %}
{% for error in line_result.errors %} -
{{ error|raw }}
+
{{ error }}
{% endfor %}
{% endif %} {% if line_result.warnings is not empty %}
{% for warning in line_result.warnings %} -
{{ warning|raw }}
+
{{ warning }}
{% endfor %}
{% endif %} {% if line_result.info is not empty %}
{% for info in line_result.info %} -
{{ info|raw }}
+
{{ info }}
{% endfor %}
{% endif %} diff --git a/templates/projects/import_bom_map_fields.html.twig b/templates/projects/import_bom_map_fields.html.twig index ee1e23ef..b272be64 100644 --- a/templates/projects/import_bom_map_fields.html.twig +++ b/templates/projects/import_bom_map_fields.html.twig @@ -132,8 +132,8 @@