From 1346abf0e5187976a80a0842208058ee77d40a5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:50:59 +0100 Subject: [PATCH 01/17] Bump docker/build-push-action from 6.16.0 to 6.17.0 (#3541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.16.0 to 6.17.0.
Release notes

Sourced from docker/build-push-action's releases.

v6.17.0

[!NOTE] Build record is now exported using the buildx history export command instead of the legacy export-build tool.

Full Changelog: https://github.com/docker/build-push-action/compare/v6.16.0...v6.17.0

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=6.16.0&new-version=6.17.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/PR-Demo-Comment-with-react.yml | 2 +- .github/workflows/push-docker.yml | 6 +++--- .github/workflows/testdriver.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index adb3e33cf..14566855b 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -180,7 +180,7 @@ jobs: password: ${{ secrets.DOCKER_HUB_API }} - name: Build and push PR-specific image - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0 with: context: . file: ./Dockerfile diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml index e4532ff59..410c294d0 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -90,7 +90,7 @@ jobs: - name: Build and push main Dockerfile id: build-push-regular - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0 with: builder: ${{ steps.buildx.outputs.name }} context: . @@ -135,7 +135,7 @@ jobs: - name: Build and push Dockerfile-ultra-lite id: build-push-lite - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0 if: github.ref != 'refs/heads/main' with: context: . @@ -166,7 +166,7 @@ jobs: - name: Build and push main Dockerfile fat id: build-push-fat - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0 if: github.ref != 'refs/heads/main' with: builder: ${{ steps.buildx.outputs.name }} diff --git a/.github/workflows/testdriver.yml b/.github/workflows/testdriver.yml index 68c4fabb2..07a23defe 100644 --- a/.github/workflows/testdriver.yml +++ b/.github/workflows/testdriver.yml @@ -46,7 +46,7 @@ jobs: password: ${{ secrets.DOCKER_HUB_API }} - name: Build and push test image - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0 with: context: . file: ./Dockerfile From 74fcf01d033140d0dfd8bab2850cbea0d1fc6ab6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:51:13 +0100 Subject: [PATCH 02/17] Bump github/codeql-action from 3.28.17 to 3.28.18 (#3542) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.17 to 3.28.18.
Release notes

Sourced from github/codeql-action's releases.

v3.28.18

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

3.28.18 - 16 May 2025

  • Update default CodeQL bundle version to 2.21.3. #2893
  • Skip validating SARIF produced by CodeQL for improved performance. #2894
  • The number of threads and amount of RAM used by CodeQL can now be set via the CODEQL_THREADS and CODEQL_RAM runner environment variables. If set, these environment variables override the threads and ram inputs respectively. #2891

See the full CHANGELOG.md for more information.

Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

[UNRELEASED]

No user facing changes.

3.28.18 - 16 May 2025

  • Update default CodeQL bundle version to 2.21.3. #2893
  • Skip validating SARIF produced by CodeQL for improved performance. #2894
  • The number of threads and amount of RAM used by CodeQL can now be set via the CODEQL_THREADS and CODEQL_RAM runner environment variables. If set, these environment variables override the threads and ram inputs respectively. #2891

3.28.17 - 02 May 2025

  • Update default CodeQL bundle version to 2.21.2. #2872

3.28.16 - 23 Apr 2025

  • Update default CodeQL bundle version to 2.21.1. #2863

3.28.15 - 07 Apr 2025

  • Fix bug where the action would fail if it tried to produce a debug artifact with more than 65535 files. #2842

3.28.14 - 07 Apr 2025

  • Update default CodeQL bundle version to 2.21.0. #2838

3.28.13 - 24 Mar 2025

No user facing changes.

3.28.12 - 19 Mar 2025

  • Dependency caching should now cache more dependencies for Java build-mode: none extractions. This should speed up workflows and avoid inconsistent alerts in some cases.
  • Update default CodeQL bundle version to 2.20.7. #2810

3.28.11 - 07 Mar 2025

  • Update default CodeQL bundle version to 2.20.6. #2793

3.28.10 - 21 Feb 2025

  • Update default CodeQL bundle version to 2.20.5. #2772
  • Address an issue where the CodeQL Bundle would occasionally fail to decompress on macOS. #2768

3.28.9 - 07 Feb 2025

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=3.28.17&new-version=3.28.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3c2d59e3e..8c6485b7b 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -74,6 +74,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17 + uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: sarif_file: results.sarif From f290f62e2328b9bf32470664eaea24c1153b3711 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:51:32 +0100 Subject: [PATCH 03/17] Bump actions/dependency-review-action from 4.7.0 to 4.7.1 (#3543) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4.7.0 to 4.7.1.
Release notes

Sourced from actions/dependency-review-action's releases.

v4.7.1

  • Packages added to allow-dependencies-licenses will be allowed even if the package in question has no license information #889
  • License expressions (e.g. Ruby OR GPL-2.0) in the allow list are automatically discarded so that they don't invalidate the whole allow list, which should just be license identifier (e.g. Ruby)
Commits
  • da24556 Merge pull request #933 from actions/dangoor/471-release
  • 9af0caf Bump version number for 4.7.1
  • d8f2df2 Merge pull request #932 from actions/907-disallow-expression
  • 6e9307a Discard allow list entries that are not SPDX IDs
  • 8805179 Merge pull request #930 from actions/889-allow-no-license
  • 014300b Update build
  • 34486f3 Check namespaces when excluding license checks
  • 9b155d6 Update build
  • f199659 Allowing dependencies works with no licenses
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/dependency-review-action&package-manager=github_actions&previous-version=4.7.0&new-version=4.7.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 0cdd47933..5a662f423 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -24,4 +24,4 @@ jobs: - name: "Checkout Repository" uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: "Dependency Review" - uses: actions/dependency-review-action@38ecb5b593bf0eb19e335c03f97670f792489a8b # v4.7.0 + uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 From 1f56ccfc99ddf4a677063aa59f0159efaaec2d93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:51:52 +0100 Subject: [PATCH 04/17] Bump gradle/actions from 4.3.1 to 4.4.0 (#3544) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [gradle/actions](https://github.com/gradle/actions) from 4.3.1 to 4.4.0.
Release notes

Sourced from gradle/actions's releases.

v4.4.0

This release updates 2 downstream components:

  • Develocity injection has been updated to v2.0
    • Some environment variables related to Develocity injection have been renamed. All vars now being with DEVELOCITY_INJECTION_. Check the docs for more details.
  • Dependency-graph plugin has been updated to v1.4.0
    • The 'detector' values included in the generated graph can now be configured via environment variables.

What's Changed

New Contributors

Full Changelog: https://github.com/gradle/actions/compare/v4.3.1...v4.4.0

Commits
  • 8379f6a Use v1.4.0 of dependency graph plugin (#638)
  • 9f79b5f [bot] Update dist directory
  • e093fac Bump the npm-dependencies group in /sources with 5 updates (#636)
  • 768a17f Bump the npm-dependencies group in /sources with 2 updates (#635)
  • 3654113 [bot] Update dist directory
  • 2ad385c Replace use of typed-rest-client with @​actions/http-client (#634)
  • 95dcf96 [bot] Update dist directory
  • 2e3238a Bump actions/download-artifact from 4.2.1 to 4.3.0 in /.github/actions/init-i...
  • 39dddb8 Remove direct use of octokit/request-error (#632)
  • 755ed7d [bot] Update dist directory
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gradle/actions&package-manager=github_actions&previous-version=4.3.1&new-version=4.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/licenses-update.yml | 2 +- .github/workflows/multiOSReleases.yml | 4 ++-- .github/workflows/push-docker.yml | 2 +- .github/workflows/releaseArtifacts.yml | 2 +- .github/workflows/sonarqube.yml | 2 +- .github/workflows/swagger.yml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index f2ab49f88..a810dbeb0 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -38,7 +38,7 @@ jobs: java-version: "17" distribution: "adopt" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 - name: check the licenses for compatibility run: ./gradlew clean checkLicense diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index b078e4015..dd8f54a9b 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -68,7 +68,7 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 @@ -156,7 +156,7 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml index 410c294d0..ab45d3a52 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -30,7 +30,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 diff --git a/.github/workflows/releaseArtifacts.yml b/.github/workflows/releaseArtifacts.yml index c0d23ce19..71be7b03a 100644 --- a/.github/workflows/releaseArtifacts.yml +++ b/.github/workflows/releaseArtifacts.yml @@ -35,7 +35,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index ddf0980ab..f9ab27ecc 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -27,7 +27,7 @@ jobs: fetch-depth: 0 - name: Setup Gradle - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 - name: Build and analyze with Gradle env: diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 19c0aaa89..0e06cb1ee 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -26,7 +26,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 - name: Generate Swagger documentation run: ./gradlew generateOpenApiDocs From 89992fe6436230398ac759619e2dff4673e7563f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:52:04 +0100 Subject: [PATCH 05/17] Bump org.springframework:spring-jdbc from 6.2.6 to 6.2.7 (#3545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.springframework:spring-jdbc](https://github.com/spring-projects/spring-framework) from 6.2.6 to 6.2.7.
Release notes

Sourced from org.springframework:spring-jdbc's releases.

v6.2.7

:star: New Features

  • Forward more methods to underlying InputStream in NonClosingInputStream #34893
  • Introduce Spring property for the default property placeholder escape character #34865
  • Close ApplicationContext once AOT processing has completed #34841
  • Fix AbstractJackson2HttpMessageConverter#getObjectMappersForType nullness #34811
  • Add option for case-insensitive match to PatternMatchUtils #34801
  • RestClient @RequestBody parameters lose generic type information when creating HTTP service beans #34793
  • Adds option to set Principal in MockServerWebExchange #34789

:lady_beetle: Bug Fixes

  • Beans created by FactoryBean are not considered as autowiring candidates if another thread holds a singletonLock #34902
  • PropertySourcesPlaceholderConfigurer placeholder resolution fails in several scenarios #34861
  • HttpComponentsClientHttpRequestFactory setConnectionRequestTimeout not working with httpclient 5.3.1 #34851
  • Fragment.create() requires mutable map - which is unusable when used with Kotlin #34848
  • Duplicate BeanOverrideHandler discovered in @Nested test case with superclass from different class or in interface implemented multiple times #34844
  • Accidental ClassLoader defineClass enforcement after #34677 #34824
  • HttpEntity.EMPTY headers should not be possible to mutate via HttpHeaders constructor #34812
  • AbstractFileResolvingResource.exists incorrectly reports result for resources inside of spring-boot executable jar #34796
  • Correctly expand query param with same name from URI variables array #34783
  • R2DBC NamedParameterUtils only expands reused collection parameter once #34768
  • PathMatchingResourcePatternResolver wrongly assumes that target/classes always exists #34764

:notebook_with_decorative_cover: Documentation

  • Clarify CompositePropertySource behavior for EnumerablePropertySource contract #34886
  • Javadoc and @Nullable annotation for servletContext parameter of ConfigurableWebEnvironment.initPropertySources are contradictory #34845
  • Spring MVC: @EnableAsync needs to be redeclared for each ApplicationContext #34843
  • Provide a working example instead of unclear placeholders #34828

:hammer: Dependency Upgrades

  • Upgrade to Micrometer 1.14.7 #34889
  • Upgrade to Reactor 2024.0.6 #34898

:heart: Contributors

Thank you to all the contributors who worked on this release:

@​Artur-, @​blake-bauman, @​iifawzi, @​kilink, @​quaff, @​whlit, and @​zzoe2346

Commits
  • ba590ac Release v6.2.7
  • ee62701 Make use of PatternMatchUtils ignoreCase option
  • fa168ca Revise FactoryBean locking behavior for strict/lenient consistency
  • 3c228a5 Add missing @​since tags in PatternMatchUtils
  • 9bf6b8c Upgrade to Reactor 2024.0.6
  • 37ecdd1 Forward more methods to underlying InputStream in NonClosingInputStream
  • 73f1c5a Polishing
  • 4d296fb Upgrade to Micrometer 1.14.7
  • 6a94444 Clarify CompositePropertySource behavior for EnumerablePropertySource contract
  • 03ae97b Introduce Spring property for default escape character for placeholders
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework:spring-jdbc&package-manager=gradle&previous-version=6.2.6&new-version=6.2.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3bea0bd14..37f364cd9 100644 --- a/build.gradle +++ b/build.gradle @@ -459,7 +459,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-mail:$springBootVersion" implementation "org.springframework.session:spring-session-core:3.4.3" - implementation "org.springframework:spring-jdbc:6.2.6" + implementation "org.springframework:spring-jdbc:6.2.7" implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5' // Don't upgrade h2database From 9aa692674f7b5b6e42c18b574497def1e3ef734a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:52:15 +0100 Subject: [PATCH 06/17] Bump org.sonarqube from 6.1.0.5360 to 6.2.0.5505 (#3546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps org.sonarqube from 6.1.0.5360 to 6.2.0.5505. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.sonarqube&package-manager=gradle&previous-version=6.1.0.5360&new-version=6.2.0.5505)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 37f364cd9..6cbd823e2 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ plugins { id "com.github.jk1.dependency-license-report" version "2.9" //id "nebula.lint" version "19.0.3" id("org.panteleyev.jpackageplugin") version "1.6.1" - id "org.sonarqube" version "6.1.0.5360" + id "org.sonarqube" version "6.2.0.5505" } import com.github.jk1.license.render.* From 8ecd4e9c361ec8de46229d30bb932088032f8a65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:52:38 +0100 Subject: [PATCH 07/17] Bump org.springframework:spring-webmvc from 6.2.6 to 6.2.7 (#3547) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [org.springframework:spring-webmvc](https://github.com/spring-projects/spring-framework) from 6.2.6 to 6.2.7.
Release notes

Sourced from org.springframework:spring-webmvc's releases.

v6.2.7

:star: New Features

  • Forward more methods to underlying InputStream in NonClosingInputStream #34893
  • Introduce Spring property for the default property placeholder escape character #34865
  • Close ApplicationContext once AOT processing has completed #34841
  • Fix AbstractJackson2HttpMessageConverter#getObjectMappersForType nullness #34811
  • Add option for case-insensitive match to PatternMatchUtils #34801
  • RestClient @RequestBody parameters lose generic type information when creating HTTP service beans #34793
  • Adds option to set Principal in MockServerWebExchange #34789

:lady_beetle: Bug Fixes

  • Beans created by FactoryBean are not considered as autowiring candidates if another thread holds a singletonLock #34902
  • PropertySourcesPlaceholderConfigurer placeholder resolution fails in several scenarios #34861
  • HttpComponentsClientHttpRequestFactory setConnectionRequestTimeout not working with httpclient 5.3.1 #34851
  • Fragment.create() requires mutable map - which is unusable when used with Kotlin #34848
  • Duplicate BeanOverrideHandler discovered in @Nested test case with superclass from different class or in interface implemented multiple times #34844
  • Accidental ClassLoader defineClass enforcement after #34677 #34824
  • HttpEntity.EMPTY headers should not be possible to mutate via HttpHeaders constructor #34812
  • AbstractFileResolvingResource.exists incorrectly reports result for resources inside of spring-boot executable jar #34796
  • Correctly expand query param with same name from URI variables array #34783
  • R2DBC NamedParameterUtils only expands reused collection parameter once #34768
  • PathMatchingResourcePatternResolver wrongly assumes that target/classes always exists #34764

:notebook_with_decorative_cover: Documentation

  • Clarify CompositePropertySource behavior for EnumerablePropertySource contract #34886
  • Javadoc and @Nullable annotation for servletContext parameter of ConfigurableWebEnvironment.initPropertySources are contradictory #34845
  • Spring MVC: @EnableAsync needs to be redeclared for each ApplicationContext #34843
  • Provide a working example instead of unclear placeholders #34828

:hammer: Dependency Upgrades

  • Upgrade to Micrometer 1.14.7 #34889
  • Upgrade to Reactor 2024.0.6 #34898

:heart: Contributors

Thank you to all the contributors who worked on this release:

@​Artur-, @​blake-bauman, @​iifawzi, @​kilink, @​quaff, @​whlit, and @​zzoe2346

Commits
  • ba590ac Release v6.2.7
  • ee62701 Make use of PatternMatchUtils ignoreCase option
  • fa168ca Revise FactoryBean locking behavior for strict/lenient consistency
  • 3c228a5 Add missing @​since tags in PatternMatchUtils
  • 9bf6b8c Upgrade to Reactor 2024.0.6
  • 37ecdd1 Forward more methods to underlying InputStream in NonClosingInputStream
  • 73f1c5a Polishing
  • 4d296fb Upgrade to Micrometer 1.14.7
  • 6a94444 Clarify CompositePropertySource behavior for EnumerablePropertySource contract
  • 03ae97b Introduce Spring property for default escape character for placeholders
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework:spring-webmvc&package-manager=gradle&previous-version=6.2.6&new-version=6.2.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6cbd823e2..2725c73cd 100644 --- a/build.gradle +++ b/build.gradle @@ -434,7 +434,7 @@ dependencies { } //security updates - implementation "org.springframework:spring-webmvc:6.2.6" + implementation "org.springframework:spring-webmvc:6.2.7" implementation("io.github.pixee:java-security-toolkit:1.2.1") From f50f7230d01a126e356e6c9f0f12ce039958ad92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:52:50 +0100 Subject: [PATCH 08/17] Bump org.springframework.security:spring-security-saml2-service-provider from 6.4.5 to 6.5.0 (#3549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [org.springframework.security:spring-security-saml2-service-provider](https://github.com/spring-projects/spring-security) from 6.4.5 to 6.5.0.
Release notes

Sourced from org.springframework.security:spring-security-saml2-service-provider's releases.

6.5.0

:star: New Features

  • Add documentation for DPoP support #17072
  • Add logging to CsrfTokenRequestHandler implementations #16994
  • Add mapping for DPoP in DefaultMapOAuth2AccessTokenResponseConverter #16806
  • Bump Gradle Wrapper from 8.13 to 8.14 #17018
  • ClientRegistrations.fromIssuerLocation does not include failure information #17015
  • Fix Typo In SubjectDnX509PrincipalExtractorTests #16997
  • Implement internal cache in JtiClaimValidator #17107
  • Polish javadoc #16924
  • Remove unused classes #16935
  • Replace NimbusOpaqueTokenIntrospector with SpringOpaqueTokenIntrospector in Documentation #16962
  • RequestHeaderAuthenticationFilter creates a session even if not configured to do so #17147

:beetle: Bug Fixes

  • Add FunctionalInterface To X509PrincipalExtractor #16952
  • Change NonNull import from reactor to spring #16571
  • Fix DPoP jkt claim to be JWK SHA-256 thumbprint #17080
  • Minor error in the Handling Logouts documentation #17049
  • SecurityAnnotationScanner's method comparison should use .equals #17145
  • Use proper configuration key in Opaque Token documentation #17014

:hammer: Dependency Upgrades

  • Bump com.fasterxml.jackson:jackson-bom from 2.18.3 to 2.18.4 #17069
  • Bump com.fasterxml.jackson:jackson-bom from 2.18.3 to 2.19.0 #16995
  • Bump com.google.code.gson:gson from 2.13.0 to 2.13.1 #16990
  • Bump com.webauthn4j:webauthn4j-core from 0.29.0.RELEASE to 0.29.1.RELEASE #17024
  • Bump com.webauthn4j:webauthn4j-core from 0.29.1.RELEASE to 0.29.2.RELEASE #17095
  • Bump io.micrometer:micrometer-observation from 1.14.6 to 1.14.7 #17096
  • Bump io.mockk:mockk from 1.14.0 to 1.14.2 #17019
  • Bump io.projectreactor:reactor-bom from 2023.0.17 to 2023.0.18 #17111
  • Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to 1.0.6 #17040
  • Bump org-apache-maven-resolver from 1.9.22 to 1.9.23 #17088
  • Bump org-eclipse-jetty from 11.0.24 to 11.0.25 #16761
  • Bump org.hibernate.orm:hibernate-core from 6.6.13.Final to 6.6.14.Final #17089
  • Bump org.hibernate.orm:hibernate-core from 6.6.14.Final to 6.6.15.Final #17105
  • Bump org.seleniumhq.selenium:selenium-java from 4.31.0 to 4.32.0 #17037
  • Bump org.springframework.data:spring-data-bom from 2024.1.4 to 2024.1.5 #16981
  • Bump org.springframework.data:spring-data-bom from 2024.1.5 to 2024.1.6 #17137
  • Bump org.springframework:spring-framework-bom from 6.2.6 to 6.2.7 #17124

:nut_and_bolt: Build Updates

:heart: Contributors

... (truncated)

Commits
  • 0fd0e93 Release 6.5.0
  • 78dd02a Merge branch '6.4.x' into 6.5.x
  • edc8735 Merge branch '6.3.x' into 6.4.x
  • cae3467 Improve AbstractPreAuthenticatedProcessingFilter docs
  • 9a8f9a9 Merge branch '6.4.x' into 6.5.x
  • c972de5 Use .equals to Compare Methods
  • bf2aaa1 Use .equals to Compare Methods
  • 6fb0591 Merge branch 'gradle/6.5.x/org.springframework.data-spring-data-bom-2024.1.6'...
  • 390972c Merge branch '6.4.x' into 6.5.x
  • 3690517 Merge branch 'gradle/6.4.x/org.springframework.data-spring-data-bom-2024.1.6'...
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework.security:spring-security-saml2-service-provider&package-manager=gradle&previous-version=6.4.5&new-version=6.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2725c73cd..f7a086a64 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ ext { imageioVersion = "3.12.0" lombokVersion = "1.18.38" bouncycastleVersion = "1.80" - springSecuritySamlVersion = "6.4.5" + springSecuritySamlVersion = "6.5.0" openSamlVersion = "4.3.2" tempJrePath = null } From b9dd78ced6335e2aadf94fa21bc8f9ba87a9ccd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:53:02 +0100 Subject: [PATCH 09/17] Bump io.micrometer:micrometer-core from 1.14.7 to 1.15.0 (#3550) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.14.7 to 1.15.0.
Release notes

Sourced from io.micrometer:micrometer-core's releases.

1.15.0

:star: New Features

  • Further enhancement to OtlpMetricsSender #6025
  • Make Prometheus Metric and Label naming conventions consistent #5923
  • Metrics for Executors.newVirtualThreadPerTaskExecutor() #5488
  • Metrics for live virtual threads #5950
  • More flexible OTLP per meter configuration #6099
  • Prometheus/OpenMetrics _created timestamp #2625
  • Make jvm.classes.unloaded description generic #5745
  • Use String.toLowerCase()/toUpperCase() with Locale.ROOT consistently #5711
  • Use failWithActualExpectedAndMessage() where possible #5696
  • Provide target host/port info in ObservationExecChainHandler when HttpHostConnectException is thrown #5615
  • Enable Gauge builders to take a subclass of Number #5601
  • micrometer-observation-test support for assertions on events #5576
  • Log delta count in addition to throughput in LoggingMeterRegistry #5548
  • Add peer name and port to gRPC observation contexts #3512
  • Use direct equals call instead of Objects.equals wrapper #5840
  • Remove special handling of 404/301 from JDK HTTP client instrumentation #5838
  • Make Timer and LongTaskTimer output similar in LoggingMeterRegistry #5835
  • Remove special handling of 404 and redirection statuses from Jetty client instrumentation #5825
  • Log deprecation warning when creating SignalFxMeterRegistry #5824
  • Log metrics recording failures in CountedAspect and TimedAspect #5820
  • Remove special handling of 404/301 from OkHttp instrumentation #5814
  • Support AutoShutdownDelegatedExecutorService in ExecutorServiceMetrics #5811
  • Deprecate micrometer-registry-signalfx in favor of micrometer-registry-otlp #5807
  • Rebind Log4j2Metrics when LoggerContext#reconfigure is called #5756
  • Send metrics via any protocol in the OTLP Registry #5690
  • Improve average performance of DefaultLongTaskTimer for out-of-order stopping #5591
  • Improve OtlpMetricsSender API #5994
  • Support configuring exponential histograms at the meter level #5459
  • Allow TimedAspect/CountedAspect to create tags based on method result #3058

:lady_beetle: Bug Fixes

  • Do not leak OTLP types on public-facing API #5699
  • micrometer-observation-test brings unnecessary JUnit dependencies, leading to conflicts #6012

:hammer: Dependency Upgrades

  • Bump io.opentelemetry.proto:opentelemetry-proto from 1.4.0-alpha to 1.5.0-alpha #5798
  • Bump com.google.cloud:libraries-bom from 26.55.0 to 26.56.0 #5991
  • Bump com.google.cloud:google-cloud-monitoring from 3.59.0 to 3.60.0 #5986
  • Bump com.google.auth:google-auth-library-oauth2-http from 1.32.1 to 1.33.0 #5963
  • Bump software.amazon.awssdk:cloudwatch from 2.29.46 to 2.30.11 #5863

:heart: Contributors

Thank you to all the contributors who worked on this release:

... (truncated)

Commits
  • e13042b Bump software.amazon.awssdk:cloudwatch from 2.31.40 to 2.31.41 (#6228)
  • 571793b Merge branch '1.14.x'
  • 315c1b1 Merge branch '1.13.x' into 1.14.x
  • a3ae027 Bump com.tngtech.archunit:archunit-junit5 from 1.3.1 to 1.3.2 (#6225)
  • ac6c26f Merge branch '1.14.x'
  • 163203f Add missing colons in "Environment" section in bug_report.md (#6223)
  • 1713fee Bump maven-resolver from 1.9.22 to 1.9.23 (#6222)
  • e315484 Bump software.amazon.awssdk:cloudwatch from 2.31.39 to 2.31.40 (#6221)
  • d6b8d4e Bump com.google.cloud:libraries-bom from 26.59.0 to 26.60.0 (#6220)
  • 121056e Bump software.amazon.awssdk:cloudwatch from 2.31.38 to 2.31.39 (#6217)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=io.micrometer:micrometer-core&package-manager=gradle&previous-version=1.14.7&new-version=1.15.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f7a086a64..0c9279795 100644 --- a/build.gradle +++ b/build.gradle @@ -528,7 +528,7 @@ dependencies { implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion" implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion" implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion" - implementation "io.micrometer:micrometer-core:1.14.7" + implementation "io.micrometer:micrometer-core:1.15.0" implementation group: "com.google.zxing", name: "core", version: "3.5.3" // https://mvnrepository.com/artifact/org.commonmark/commonmark implementation "org.commonmark:commonmark:0.24.0" From 9514370cc3cd89c56923995399257736a84d94d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 11:58:23 +0100 Subject: [PATCH 10/17] Bump org.gradle.toolchains.foojay-resolver-convention from 0.10.0 to 1.0.0 (#3552) Bumps org.gradle.toolchains.foojay-resolver-convention from 0.10.0 to 1.0.0. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.gradle.toolchains.foojay-resolver-convention&package-manager=gradle&previous-version=0.10.0&new-version=1.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 6f039dc93..49d1c98ad 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ plugins { // Apply the foojay-resolver plugin to allow automatic download of JDKs - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } rootProject.name = 'Stirling-PDF' From d59e39b4b61112d6569b6b1f39b330045dd759c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 12:00:31 +0100 Subject: [PATCH 11/17] Bump org.mockito:mockito-core from 5.11.0 to 5.17.0 (#3551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.11.0 to 5.17.0.
Release notes

Sourced from org.mockito:mockito-core's releases.

v5.17.0

Changelog generated by Shipkit Changelog Gradle Plugin

5.17.0

v5.16.1

Changelog generated by Shipkit Changelog Gradle Plugin

5.16.1

v5.16.0

Changelog generated by Shipkit Changelog Gradle Plugin

5.16.0

v5.15.2

Changelog generated by Shipkit Changelog Gradle Plugin

5.15.2

... (truncated)

Commits
  • 7764992 Remove mention of mockito-inline from mockmaker exception (#3628)
  • ee92ad4 Fix broken banner image link (#3632)
  • 3edab52 Clarify structure of commit messages (#3626)
  • bfab743 Fall back to Throwable Location strategy on Android (#3619)
  • 4f469c8 MockitoExtension fails cleanup when aborted before setup (#3623)
  • 1764e62 Update links to javadoc.io (#3616)
  • 1e029d7 Add missing requirement to objenesis.
  • d000e63 Rework of injection strategy in the context of modules (#3608)
  • 0215884 Remove Arrays.asList from critical stubbing path in GenericMetadataSupport (#...
  • d185035 Add reference to Gradle documentation on how to make task relocatable (#3606)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.mockito:mockito-core&package-manager=gradle&previous-version=5.11.0&new-version=5.17.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0c9279795..9adf2f1b5 100644 --- a/build.gradle +++ b/build.gradle @@ -544,7 +544,7 @@ dependencies { annotationProcessor "org.projectlombok:lombok:$lombokVersion" // Mockito (core) - testImplementation 'org.mockito:mockito-core:5.11.0' + testImplementation 'org.mockito:mockito-core:5.17.0' testRuntimeOnly 'org.mockito:mockito-inline:5.2.0' From 9fe49c494d580983c793e65b476d0734a3d8383c Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 20 May 2025 12:02:01 +0100 Subject: [PATCH 12/17] Fix test compilation around pipeline processor (#3554) ## Summary - allow tests to spy on PipelineProcessor web requests - fix ResponseEntity usage in PipelineProcessorTest ## Testing - `./gradlew test --offline` *(fails: No route to host while downloading gradle-8.14-all.zip)* --- .../api/pipeline/PipelineProcessor.java | 7 +- .../api/pipeline/PipelineProcessorTest.java | 76 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java diff --git a/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessor.java b/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessor.java index 2833ee99e..12c131f59 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessor.java +++ b/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessor.java @@ -93,6 +93,7 @@ public class PipelineProcessor { ByteArrayOutputStream logStream = new ByteArrayOutputStream(); PrintStream logPrintStream = new PrintStream(logStream); boolean hasErrors = false; + boolean filtersApplied = false; for (PipelineOperation pipelineOperation : config.getOperations()) { String operation = pipelineOperation.getOperation(); boolean isMultiInputOperation = apiDocService.isMultiInput(operation); @@ -134,7 +135,7 @@ public class PipelineProcessor { if (operation.startsWith("filter-") && (response.getBody() == null || response.getBody().length == 0)) { - result.setFiltersApplied(true); + filtersApplied = true; log.info("Skipping file due to filtering {}", operation); continue; } @@ -215,12 +216,12 @@ public class PipelineProcessor { log.error("Errors occurred during processing. Log: {}", logStream.toString()); } result.setHasErrors(hasErrors); - result.setFiltersApplied(hasErrors); + result.setFiltersApplied(filtersApplied); result.setOutputFiles(outputFiles); return result; } - private ResponseEntity sendWebRequest(String url, MultiValueMap body) { + /* package */ ResponseEntity sendWebRequest(String url, MultiValueMap body) { RestTemplate restTemplate = new RestTemplate(); // Set up headers, including API key HttpHeaders headers = new HttpHeaders(); diff --git a/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java b/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java new file mode 100644 index 000000000..3e22d2cc0 --- /dev/null +++ b/src/test/java/stirling/software/SPDF/controller/api/pipeline/PipelineProcessorTest.java @@ -0,0 +1,76 @@ +package stirling.software.SPDF.controller.api.pipeline; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import jakarta.servlet.ServletContext; + +import stirling.software.SPDF.model.PipelineConfig; +import stirling.software.SPDF.model.PipelineOperation; +import stirling.software.SPDF.model.PipelineResult; + +@ExtendWith(MockitoExtension.class) +class PipelineProcessorTest { + + @Mock + ApiDocService apiDocService; + + @Mock + UserServiceInterface userService; + + @Mock + ServletContext servletContext; + + PipelineProcessor pipelineProcessor; + + @BeforeEach + void setUp() { + pipelineProcessor = spy(new PipelineProcessor(apiDocService, userService, servletContext)); + } + + @Test + void runPipelineWithFilterSetsFlag() throws Exception { + PipelineOperation op = new PipelineOperation(); + op.setOperation("filter-page-count"); + op.setParameters(Map.of()); + PipelineConfig config = new PipelineConfig(); + config.setOperations(List.of(op)); + + Resource file = new ByteArrayResource("data".getBytes()) { + @Override + public String getFilename() { + return "test.pdf"; + } + }; + + List files = List.of(file); + + when(apiDocService.isMultiInput("filter-page-count")).thenReturn(false); + when(apiDocService.getExtensionTypes(false, "filter-page-count")).thenReturn(List.of("pdf")); + + doReturn(new ResponseEntity<>(new byte[0], HttpStatus.OK)) + .when(pipelineProcessor) + .sendWebRequest(anyString(), any()); + + PipelineResult result = pipelineProcessor.runPipelineAgainstFiles(files, config); + + assertTrue(result.isFiltersApplied(), "Filter flag should be true when operation filters file"); + assertFalse(result.isHasErrors(), "No errors should occur"); + assertTrue(result.getOutputFiles().isEmpty(), "Filtered file list should be empty"); + } +} + From 218d21f07a96a49ab37e1bb95488c0646a39c001 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 20 May 2025 12:02:10 +0100 Subject: [PATCH 13/17] Update AGENTS guidelines (#3556) ## Summary - clarify Codex contribution instructions - remove `test.sh` reference and require `./gradlew build` - add Developer Guide, AI note and translation policy ## Testing - `./gradlew spotlessApply` - `./gradlew build` --- AGENTS.md | 24 ++ .../SPDF/EE/KeygenLicenseVerifier.java | 210 +++++++++++------- .../service/CustomPDFDocumentFactoryTest.java | 104 ++++----- .../SPDF/service/SpyPDFDocumentFactory.java | 16 +- .../SPDF/utils/CustomHtmlSanitizerTest.java | 41 ++-- .../software/SPDF/utils/PDFToFileTest.java | 12 +- 6 files changed, 229 insertions(+), 178 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..461d26c07 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +# Codex Contribution Guidelines for Stirling-PDF + +This file provides high-level instructions for Codex when modifying any files within this repository. Follow these rules to ensure changes remain consistent with the existing project structure. + +## 1. Code Style and Formatting +- Respect the `.editorconfig` settings located in the repository root. Java files use 4 spaces; HTML, JS, and Python generally use 2 spaces. Lines should end with `LF`. +- Format Java code with `./gradlew spotlessApply` before committing. +- Review `DeveloperGuide.md` for project structure and design details before making significant changes. + +## 2. Testing +- Run `./gradlew build` before committing changes to ensure the project compiles. +- If the build cannot complete due to environment restrictions, DO NOT COMMIT THE CHANGE + +## 3. Commits +- Keep commits focused. Group related changes together and provide concise commit messages. +- Ensure the working tree is clean (`git status`) before concluding your work. + +## 4. Pull Requests +- Summarize what was changed and why. Include build results from `./gradlew build` in the PR description. +- Note that the code was generated with the assistance of AI. + +## 5. Translations +- Only modify `messages_en_GB.properties` when adding or updating translations. + diff --git a/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java b/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java index 2be506bec..092665dc3 100644 --- a/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java +++ b/src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java @@ -47,19 +47,20 @@ public class KeygenLicenseVerifier { private static final ObjectMapper objectMapper = new ObjectMapper(); private final ApplicationProperties applicationProperties; - + // Shared HTTP client for connection pooling - private static final HttpClient httpClient = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .connectTimeout(java.time.Duration.ofSeconds(10)) - .build(); - + private static final HttpClient httpClient = + HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .connectTimeout(java.time.Duration.ofSeconds(10)) + .build(); + // License metadata context class to avoid shared mutable state private static class LicenseContext { private boolean isFloatingLicense = false; private int maxMachines = 1; // Default to 1 if not specified private boolean isEnterpriseLicense = false; - + public LicenseContext() {} } @@ -248,7 +249,7 @@ public class KeygenLicenseVerifier { // Check for floating license context.isFloatingLicense = attributesObj.optBoolean("floating", false); context.maxMachines = attributesObj.optInt("maxMachines", 1); - + // Extract metadata JSONObject metadataObj = attributesObj.optJSONObject("metadata"); if (metadataObj != null) { @@ -411,14 +412,16 @@ public class KeygenLicenseVerifier { // Check for floating license in policy boolean policyFloating = policyObj.optBoolean("floating", false); int policyMaxMachines = policyObj.optInt("maxMachines", 1); - + // Policy settings take precedence if (policyFloating) { context.isFloatingLicense = true; context.maxMachines = policyMaxMachines; - log.info("Policy defines floating license with max machines: {}", context.maxMachines); + log.info( + "Policy defines floating license with max machines: {}", + context.maxMachines); } - + // Extract max users and isEnterprise from policy or metadata int users = policyObj.optInt("users", 1); context.isEnterpriseLicense = policyObj.optBoolean("isEnterprise", false); @@ -474,7 +477,8 @@ public class KeygenLicenseVerifier { activateMachine(licenseKey, licenseId, machineFingerprint, context); if (activated) { // Revalidate after activation - validationResponse = validateLicense(licenseKey, machineFingerprint, context); + validationResponse = + validateLicense(licenseKey, machineFingerprint, context); isValid = validationResponse != null && validationResponse @@ -494,8 +498,8 @@ public class KeygenLicenseVerifier { } } - private JsonNode validateLicense(String licenseKey, String machineFingerprint, LicenseContext context) - throws Exception { + private JsonNode validateLicense( + String licenseKey, String machineFingerprint, LicenseContext context) throws Exception { String requestBody = String.format( "{\"meta\":{\"key\":\"%s\",\"scope\":{\"fingerprint\":\"%s\"}}}", @@ -514,7 +518,8 @@ public class KeygenLicenseVerifier { .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); log.info("ValidateLicenseResponse body: {}", response.body()); JsonNode jsonResponse = objectMapper.readTree(response.body()); if (response.statusCode() == 200) { @@ -527,21 +532,23 @@ public class KeygenLicenseVerifier { log.info("License validity: " + isValid); log.info("Validation detail: " + detail); log.info("Validation code: " + code); - + // Check if the license itself has floating attribute JsonNode licenseAttrs = jsonResponse.path("data").path("attributes"); if (!licenseAttrs.isMissingNode()) { context.isFloatingLicense = licenseAttrs.path("floating").asBoolean(false); context.maxMachines = licenseAttrs.path("maxMachines").asInt(1); - - log.info("License floating (from license): {}, maxMachines: {}", - context.isFloatingLicense, context.maxMachines); + + log.info( + "License floating (from license): {}, maxMachines: {}", + context.isFloatingLicense, + context.maxMachines); } - + // Also check the policy for floating license support if included JsonNode includedNode = jsonResponse.path("included"); JsonNode policyNode = null; - + if (includedNode.isArray()) { for (JsonNode node : includedNode) { if ("policies".equals(node.path("type").asText())) { @@ -550,20 +557,23 @@ public class KeygenLicenseVerifier { } } } - + if (policyNode != null) { // Check if this is a floating license from policy - boolean policyFloating = policyNode.path("attributes").path("floating").asBoolean(false); + boolean policyFloating = + policyNode.path("attributes").path("floating").asBoolean(false); int policyMaxMachines = policyNode.path("attributes").path("maxMachines").asInt(1); - + // Policy takes precedence over license attributes if (policyFloating) { context.isFloatingLicense = true; context.maxMachines = policyMaxMachines; } - - log.info("License floating (from policy): {}, maxMachines: {}", - context.isFloatingLicense, context.maxMachines); + + log.info( + "License floating (from policy): {}, maxMachines: {}", + context.isFloatingLicense, + context.maxMachines); } // Extract user count, default to 1 if not specified @@ -593,86 +603,104 @@ public class KeygenLicenseVerifier { return jsonResponse; } - private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint, - LicenseContext context) throws Exception { + private boolean activateMachine( + String licenseKey, String licenseId, String machineFingerprint, LicenseContext context) + throws Exception { // For floating licenses, we first need to check if we need to deregister any machines if (context.isFloatingLicense) { - log.info("Processing floating license activation. Max machines allowed: {}", context.maxMachines); - + log.info( + "Processing floating license activation. Max machines allowed: {}", + context.maxMachines); + // Get the current machines for this license JsonNode machinesResponse = fetchMachinesForLicense(licenseKey, licenseId); if (machinesResponse != null) { JsonNode machines = machinesResponse.path("data"); int currentMachines = machines.size(); - - log.info("Current machine count: {}, Max allowed: {}", currentMachines, context.maxMachines); - + + log.info( + "Current machine count: {}, Max allowed: {}", + currentMachines, + context.maxMachines); + // Check if the current fingerprint is already activated boolean isCurrentMachineActivated = false; String currentMachineId = null; - + for (JsonNode machine : machines) { - if (machineFingerprint.equals(machine.path("attributes").path("fingerprint").asText())) { + if (machineFingerprint.equals( + machine.path("attributes").path("fingerprint").asText())) { isCurrentMachineActivated = true; currentMachineId = machine.path("id").asText(); - log.info("Current machine is already activated with ID: {}", currentMachineId); + log.info( + "Current machine is already activated with ID: {}", + currentMachineId); break; } } - + // If the current machine is already activated, there's no need to do anything if (isCurrentMachineActivated) { log.info("Machine already activated. No action needed."); return true; } - + // If we've reached the max machines limit, we need to deregister the oldest machine if (currentMachines >= context.maxMachines) { - log.info("Max machines reached. Deregistering oldest machine to make room for the new machine."); - + log.info( + "Max machines reached. Deregistering oldest machine to make room for the new machine."); + // Find the oldest machine based on creation timestamp if (machines.size() > 0) { // Find the machine with the oldest creation date String oldestMachineId = null; java.time.Instant oldestTime = null; - + for (JsonNode machine : machines) { - String createdStr = machine.path("attributes").path("created").asText(null); + String createdStr = + machine.path("attributes").path("created").asText(null); if (createdStr != null && !createdStr.isEmpty()) { try { - java.time.Instant createdTime = java.time.Instant.parse(createdStr); + java.time.Instant createdTime = + java.time.Instant.parse(createdStr); if (oldestTime == null || createdTime.isBefore(oldestTime)) { oldestTime = createdTime; oldestMachineId = machine.path("id").asText(); } } catch (Exception e) { - log.warn("Could not parse creation time for machine: {}", e.getMessage()); + log.warn( + "Could not parse creation time for machine: {}", + e.getMessage()); } } } - + // If we couldn't determine the oldest by timestamp, use the first one if (oldestMachineId == null) { - log.warn("Could not determine oldest machine by timestamp, using first machine in list"); + log.warn( + "Could not determine oldest machine by timestamp, using first machine in list"); oldestMachineId = machines.path(0).path("id").asText(); } - + log.info("Deregistering machine with ID: {}", oldestMachineId); - + boolean deregistered = deregisterMachine(licenseKey, oldestMachineId); if (!deregistered) { - log.error("Failed to deregister machine. Cannot proceed with activation."); + log.error( + "Failed to deregister machine. Cannot proceed with activation."); return false; } - log.info("Machine deregistered successfully. Proceeding with activation of new machine."); + log.info( + "Machine deregistered successfully. Proceeding with activation of new machine."); } else { - log.error("License has reached machine limit but no machines were found to deregister. This is unexpected."); + log.error( + "License has reached machine limit but no machines were found to deregister. This is unexpected."); // We'll still try to activate, but it might fail } } } } - + // Proceed with machine activation String hostname; try { @@ -720,7 +748,8 @@ public class KeygenLicenseVerifier { .POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); log.info("activateMachine Response body: " + response.body()); if (response.statusCode() == 201) { log.info("Machine activated successfully"); @@ -738,61 +767,76 @@ public class KeygenLicenseVerifier { private String generateMachineFingerprint() { return GeneralUtils.generateMachineFingerprint(); } - + /** * Fetches all machines associated with a specific license - * + * * @param licenseKey The license key to check - * @param licenseId The license ID + * @param licenseId The license ID * @return JsonNode containing the list of machines, or null if an error occurs * @throws Exception if an error occurs during the HTTP request */ private JsonNode fetchMachinesForLicense(String licenseKey, String licenseId) throws Exception { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/licenses/" + licenseId + "/machines")) - .header("Content-Type", "application/vnd.api+json") - .header("Accept", "application/vnd.api+json") - .header("Authorization", "License " + licenseKey) - .GET() - .build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpRequest request = + HttpRequest.newBuilder() + .uri( + URI.create( + BASE_URL + + "/" + + ACCOUNT_ID + + "/licenses/" + + licenseId + + "/machines")) + .header("Content-Type", "application/vnd.api+json") + .header("Accept", "application/vnd.api+json") + .header("Authorization", "License " + licenseKey) + .GET() + .build(); + + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); log.info("fetchMachinesForLicense Response body: {}", response.body()); - + if (response.statusCode() == 200) { return objectMapper.readTree(response.body()); } else { - log.error("Error fetching machines for license. Status code: {}, error: {}", - response.statusCode(), response.body()); + log.error( + "Error fetching machines for license. Status code: {}, error: {}", + response.statusCode(), + response.body()); return null; } } - + /** * Deregisters a machine from a license - * + * * @param licenseKey The license key * @param machineId The ID of the machine to deregister * @return true if deregistration was successful, false otherwise */ private boolean deregisterMachine(String licenseKey, String machineId) { try { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/machines/" + machineId)) - .header("Content-Type", "application/vnd.api+json") - .header("Accept", "application/vnd.api+json") - .header("Authorization", "License " + licenseKey) - .DELETE() - .build(); - - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - + HttpRequest request = + HttpRequest.newBuilder() + .uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/machines/" + machineId)) + .header("Content-Type", "application/vnd.api+json") + .header("Accept", "application/vnd.api+json") + .header("Authorization", "License " + licenseKey) + .DELETE() + .build(); + + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() == 204) { log.info("Machine {} successfully deregistered", machineId); return true; } else { - log.error("Error deregistering machine. Status code: {}, error: {}", - response.statusCode(), response.body()); + log.error( + "Error deregistering machine. Status code: {}, error: {}", + response.statusCode(), + response.body()); return false; } } catch (Exception e) { diff --git a/src/test/java/stirling/software/SPDF/service/CustomPDFDocumentFactoryTest.java b/src/test/java/stirling/software/SPDF/service/CustomPDFDocumentFactoryTest.java index 035011008..7fe84416b 100644 --- a/src/test/java/stirling/software/SPDF/service/CustomPDFDocumentFactoryTest.java +++ b/src/test/java/stirling/software/SPDF/service/CustomPDFDocumentFactoryTest.java @@ -1,18 +1,17 @@ package stirling.software.SPDF.service; -import java.nio.file.Files; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import java.io.*; import java.nio.file.*; +import java.nio.file.Files; import java.util.Arrays; import org.apache.pdfbox.Loader; +import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.*; import org.apache.pdfbox.pdmodel.common.PDStream; -import org.aspectj.lang.annotation.Before; -import org.apache.pdfbox.cos.COSName; import org.junit.jupiter.api.*; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; @@ -25,7 +24,7 @@ import stirling.software.SPDF.service.SpyPDFDocumentFactory.StrategyType; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -@Execution(value = ExecutionMode.SAME_THREAD) +@Execution(value = ExecutionMode.SAME_THREAD) class CustomPDFDocumentFactoryTest { private SpyPDFDocumentFactory factory; @@ -43,12 +42,7 @@ class CustomPDFDocumentFactoryTest { } @ParameterizedTest - @CsvSource({ - "5,MEMORY_ONLY", - "20,MIXED", - "60,TEMP_FILE" - - }) + @CsvSource({"5,MEMORY_ONLY", "20,MIXED", "60,TEMP_FILE"}) void testStrategy_FileInput(int sizeMB, StrategyType expected) throws IOException { File file = writeTempFile(inflatePdf(basePdfBytes, sizeMB)); try (PDDocument doc = factory.load(file)) { @@ -57,12 +51,7 @@ class CustomPDFDocumentFactoryTest { } @ParameterizedTest - @CsvSource({ - "5,MEMORY_ONLY", - "20,MIXED", - "60,TEMP_FILE" - - }) + @CsvSource({"5,MEMORY_ONLY", "20,MIXED", "60,TEMP_FILE"}) void testStrategy_ByteArray(int sizeMB, StrategyType expected) throws IOException { byte[] inflated = inflatePdf(basePdfBytes, sizeMB); try (PDDocument doc = factory.load(inflated)) { @@ -71,12 +60,7 @@ class CustomPDFDocumentFactoryTest { } @ParameterizedTest - @CsvSource({ - "5,MEMORY_ONLY", - "20,MIXED", - "60,TEMP_FILE" - - }) + @CsvSource({"5,MEMORY_ONLY", "20,MIXED", "60,TEMP_FILE"}) void testStrategy_InputStream(int sizeMB, StrategyType expected) throws IOException { byte[] inflated = inflatePdf(basePdfBytes, sizeMB); try (PDDocument doc = factory.load(new ByteArrayInputStream(inflated))) { @@ -85,30 +69,22 @@ class CustomPDFDocumentFactoryTest { } @ParameterizedTest - @CsvSource({ - "5,MEMORY_ONLY", - "20,MIXED", - "60,TEMP_FILE" - - }) + @CsvSource({"5,MEMORY_ONLY", "20,MIXED", "60,TEMP_FILE"}) void testStrategy_MultipartFile(int sizeMB, StrategyType expected) throws IOException { byte[] inflated = inflatePdf(basePdfBytes, sizeMB); - MockMultipartFile multipart = new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated); + MockMultipartFile multipart = + new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated); try (PDDocument doc = factory.load(multipart)) { assertEquals(expected, factory.lastStrategyUsed); } } @ParameterizedTest - @CsvSource({ - "5,MEMORY_ONLY", - "20,MIXED", - "60,TEMP_FILE" - - }) + @CsvSource({"5,MEMORY_ONLY", "20,MIXED", "60,TEMP_FILE"}) void testStrategy_PDFFile(int sizeMB, StrategyType expected) throws IOException { byte[] inflated = inflatePdf(basePdfBytes, sizeMB); - MockMultipartFile multipart = new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated); + MockMultipartFile multipart = + new MockMultipartFile("file", "doc.pdf", "application/pdf", inflated); PDFFile pdfFile = new PDFFile(); pdfFile.setFileInput(multipart); try (PDDocument doc = factory.load(pdfFile)) { @@ -125,14 +101,16 @@ class CustomPDFDocumentFactoryTest { stream.getCOSObject().setItem(COSName.TYPE, COSName.XOBJECT); stream.getCOSObject().setItem(COSName.SUBTYPE, COSName.IMAGE); - doc.getDocumentCatalog().getCOSObject().setItem(COSName.getPDFName("DummyBigStream"), stream.getCOSObject()); + doc.getDocumentCatalog() + .getCOSObject() + .setItem(COSName.getPDFName("DummyBigStream"), stream.getCOSObject()); ByteArrayOutputStream out = new ByteArrayOutputStream(); doc.save(out); return out.toByteArray(); } } - + @Test void testLoadFromPath() throws IOException { File file = writeTempFile(inflatePdf(basePdfBytes, 5)); @@ -151,29 +129,29 @@ class CustomPDFDocumentFactoryTest { } // neeed to add password pdf -// @Test -// void testLoadPasswordProtectedPdfFromInputStream() throws IOException { -// try (InputStream is = getClass().getResourceAsStream("/protected.pdf")) { -// assertNotNull(is, "protected.pdf must be present in src/test/resources"); -// try (PDDocument doc = factory.load(is, "test123")) { -// assertNotNull(doc); -// } -// } -// } -// -// @Test -// void testLoadPasswordProtectedPdfFromMultipart() throws IOException { -// try (InputStream is = getClass().getResourceAsStream("/protected.pdf")) { -// assertNotNull(is, "protected.pdf must be present in src/test/resources"); -// byte[] bytes = is.readAllBytes(); -// MockMultipartFile file = new MockMultipartFile("file", "protected.pdf", "application/pdf", bytes); -// try (PDDocument doc = factory.load(file, "test123")) { -// assertNotNull(doc); -// } -// } -// } + // @Test + // void testLoadPasswordProtectedPdfFromInputStream() throws IOException { + // try (InputStream is = getClass().getResourceAsStream("/protected.pdf")) { + // assertNotNull(is, "protected.pdf must be present in src/test/resources"); + // try (PDDocument doc = factory.load(is, "test123")) { + // assertNotNull(doc); + // } + // } + // } + // + // @Test + // void testLoadPasswordProtectedPdfFromMultipart() throws IOException { + // try (InputStream is = getClass().getResourceAsStream("/protected.pdf")) { + // assertNotNull(is, "protected.pdf must be present in src/test/resources"); + // byte[] bytes = is.readAllBytes(); + // MockMultipartFile file = new MockMultipartFile("file", "protected.pdf", + // "application/pdf", bytes); + // try (PDDocument doc = factory.load(file, "test123")) { + // assertNotNull(doc); + // } + // } + // } - @Test void testLoadReadOnlySkipsPostProcessing() throws IOException { PdfMetadataService mockService = mock(PdfMetadataService.class); @@ -186,7 +164,6 @@ class CustomPDFDocumentFactoryTest { } } - @Test void testCreateNewDocument() throws IOException { try (PDDocument doc = factory.createNewDocument()) { @@ -198,7 +175,7 @@ class CustomPDFDocumentFactoryTest { void testCreateNewDocumentBasedOnOldDocument() throws IOException { byte[] inflated = inflatePdf(basePdfBytes, 5); try (PDDocument oldDoc = Loader.loadPDF(inflated); - PDDocument newDoc = factory.createNewDocumentBasedOnOldDocument(oldDoc)) { + PDDocument newDoc = factory.createNewDocumentBasedOnOldDocument(oldDoc)) { assertNotNull(newDoc); } } @@ -241,7 +218,6 @@ class CustomPDFDocumentFactoryTest { @BeforeEach void cleanup() { - System.gc(); + System.gc(); } - } diff --git a/src/test/java/stirling/software/SPDF/service/SpyPDFDocumentFactory.java b/src/test/java/stirling/software/SPDF/service/SpyPDFDocumentFactory.java index ff53246d6..c7035c17d 100644 --- a/src/test/java/stirling/software/SPDF/service/SpyPDFDocumentFactory.java +++ b/src/test/java/stirling/software/SPDF/service/SpyPDFDocumentFactory.java @@ -1,14 +1,14 @@ package stirling.software.SPDF.service; + import org.apache.pdfbox.io.RandomAccessStreamCache.StreamCacheCreateFunction; -import stirling.software.SPDF.service.CustomPDFDocumentFactory; -import stirling.software.SPDF.service.PdfMetadataService; - class SpyPDFDocumentFactory extends CustomPDFDocumentFactory { - enum StrategyType { - MEMORY_ONLY, MIXED, TEMP_FILE - } - + enum StrategyType { + MEMORY_ONLY, + MIXED, + TEMP_FILE + } + public StrategyType lastStrategyUsed; public SpyPDFDocumentFactory(PdfMetadataService service) { @@ -28,4 +28,4 @@ class SpyPDFDocumentFactory extends CustomPDFDocumentFactory { this.lastStrategyUsed = type; return super.getStreamCacheFunction(contentSize); // delegate to real behavior } -} \ No newline at end of file +} diff --git a/src/test/java/stirling/software/SPDF/utils/CustomHtmlSanitizerTest.java b/src/test/java/stirling/software/SPDF/utils/CustomHtmlSanitizerTest.java index fc79db566..978970270 100644 --- a/src/test/java/stirling/software/SPDF/utils/CustomHtmlSanitizerTest.java +++ b/src/test/java/stirling/software/SPDF/utils/CustomHtmlSanitizerTest.java @@ -27,25 +27,28 @@ class CustomHtmlSanitizerTest { private static Stream provideHtmlTestCases() { return Stream.of( - Arguments.of( - "

This is valid HTML with formatting.

", - new String[] {"

", "", ""} - ), - Arguments.of( - "

Text with bold, italic, underline, " - + "emphasis, strong, strikethrough, " - + "strike, subscript, superscript, " - + "teletype, code, big, small.

", - new String[] {"bold", "italic", "emphasis", "strong"} - ), - Arguments.of( - "
Division

Heading 1

Heading 2

Heading 3

" - + "

Heading 4

Heading 5
Heading 6
" - + "
Blockquote
  • List item
" - + "
  1. Ordered item
", - new String[] {"
", "

", "

", "
", "
    ", "
      ", "
    1. "} - ) - ); + Arguments.of( + "

      This is valid HTML with formatting.

      ", + new String[] {"

      ", "", ""}), + Arguments.of( + "

      Text with bold, italic, underline, " + + "emphasis, strong, strikethrough, " + + "strike, subscript, superscript, " + + "teletype, code, big, small.

      ", + new String[] { + "bold", + "italic", + "emphasis", + "strong" + }), + Arguments.of( + "
      Division

      Heading 1

      Heading 2

      Heading 3

      " + + "

      Heading 4

      Heading 5
      Heading 6
      " + + "
      Blockquote
      • List item
      " + + "
      1. Ordered item
      ", + new String[] { + "
      ", "

      ", "

      ", "
      ", "
        ", "
          ", "
        1. " + })); } @Test diff --git a/src/test/java/stirling/software/SPDF/utils/PDFToFileTest.java b/src/test/java/stirling/software/SPDF/utils/PDFToFileTest.java index 7960128df..38b5e9277 100644 --- a/src/test/java/stirling/software/SPDF/utils/PDFToFileTest.java +++ b/src/test/java/stirling/software/SPDF/utils/PDFToFileTest.java @@ -1,6 +1,5 @@ package stirling.software.SPDF.utils; -import io.github.pixee.security.ZipSecurity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -29,6 +28,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; +import io.github.pixee.security.ZipSecurity; + import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; /** @@ -214,7 +215,8 @@ class PDFToFileTest { // Verify the content by unzipping it try (ZipInputStream zipStream = - ZipSecurity.createHardenedInputStream(new java.io.ByteArrayInputStream(response.getBody()))) { + ZipSecurity.createHardenedInputStream( + new java.io.ByteArrayInputStream(response.getBody()))) { ZipEntry entry; boolean foundMdFiles = false; boolean foundImage = false; @@ -286,7 +288,8 @@ class PDFToFileTest { // Verify the content by unzipping it try (ZipInputStream zipStream = - ZipSecurity.createHardenedInputStream(new java.io.ByteArrayInputStream(response.getBody()))) { + ZipSecurity.createHardenedInputStream( + new java.io.ByteArrayInputStream(response.getBody()))) { ZipEntry entry; boolean foundMainHtml = false; boolean foundIndexHtml = false; @@ -437,7 +440,8 @@ class PDFToFileTest { // Verify the content by unzipping it try (ZipInputStream zipStream = - ZipSecurity.createHardenedInputStream(new java.io.ByteArrayInputStream(response.getBody()))) { + ZipSecurity.createHardenedInputStream( + new java.io.ByteArrayInputStream(response.getBody()))) { ZipEntry entry; boolean foundMainFile = false; boolean foundMediaFiles = false; From c8e25f4c5ad4be4c97c6bf797cd4e766e4fe0a43 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 20 May 2025 12:02:26 +0100 Subject: [PATCH 14/17] Fix TemplateResolver and LibreOfficeListener bugs (#3555) ## Summary - log missing exceptions in FileFallbackTemplateResolver - implement exists check for InputStreamTemplateResource - use LISTENER_PORT constant when verifying LibreOffice listener ## Testing - `./gradlew build --no-daemon` - `./gradlew test --no-daemon` --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../java/stirling/software/SPDF/LibreOfficeListener.java | 3 ++- .../software/SPDF/config/FileFallbackTemplateResolver.java | 6 +++++- .../software/SPDF/model/InputStreamTemplateResource.java | 3 +-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/LibreOfficeListener.java b/src/main/java/stirling/software/SPDF/LibreOfficeListener.java index 5b00700e8..2be2a082c 100644 --- a/src/main/java/stirling/software/SPDF/LibreOfficeListener.java +++ b/src/main/java/stirling/software/SPDF/LibreOfficeListener.java @@ -31,7 +31,8 @@ public class LibreOfficeListener { log.info("waiting for listener to start"); try (Socket socket = new Socket()) { socket.connect( - new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second + new InetSocketAddress("localhost", LISTENER_PORT), + 1000); // Timeout after 1 second return true; } catch (Exception e) { return false; diff --git a/src/main/java/stirling/software/SPDF/config/FileFallbackTemplateResolver.java b/src/main/java/stirling/software/SPDF/config/FileFallbackTemplateResolver.java index b6315db92..8073f2358 100644 --- a/src/main/java/stirling/software/SPDF/config/FileFallbackTemplateResolver.java +++ b/src/main/java/stirling/software/SPDF/config/FileFallbackTemplateResolver.java @@ -11,8 +11,11 @@ import org.thymeleaf.templateresolver.AbstractConfigurableTemplateResolver; import org.thymeleaf.templateresource.FileTemplateResource; import org.thymeleaf.templateresource.ITemplateResource; +import lombok.extern.slf4j.Slf4j; + import stirling.software.SPDF.model.InputStreamTemplateResource; +@Slf4j public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver { private final ResourceLoader resourceLoader; @@ -40,7 +43,8 @@ public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateRe return new FileTemplateResource(resource.getFile().getPath(), characterEncoding); } } catch (IOException e) { - + // Log the exception to help with debugging issues loading external templates + log.warn("Unable to read template '{}' from file system", resourceName, e); } InputStream inputStream = diff --git a/src/main/java/stirling/software/SPDF/model/InputStreamTemplateResource.java b/src/main/java/stirling/software/SPDF/model/InputStreamTemplateResource.java index b4271df02..3e0bd65e8 100644 --- a/src/main/java/stirling/software/SPDF/model/InputStreamTemplateResource.java +++ b/src/main/java/stirling/software/SPDF/model/InputStreamTemplateResource.java @@ -39,7 +39,6 @@ public class InputStreamTemplateResource implements ITemplateResource { @Override public boolean exists() { - // TODO Auto-generated method stub - return false; + return inputStream != null; } } From 46cc2e05df97cef04118ea1fde880b52f3d919ba Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Tue, 20 May 2025 12:05:18 +0100 Subject: [PATCH 15/17] Add additional unit tests for utils and EE (#3557) ## Summary - add tests for LicenseKeyChecker - expand GeneralUtils coverage - cover extra PdfUtils functionality - merge PdfUtilsMoreTest into PdfUtilsTest ## Testing - `./gradlew test --no-daemon` - `./gradlew build spotlessApply --no-daemon` --- .../SPDF/EE/LicenseKeyCheckerTest.java | 77 +++++++++++++++++++ .../utils/GeneralUtilsAdditionalTest.java | 41 ++++++++++ .../software/SPDF/utils/PdfUtilsTest.java | 73 ++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 src/test/java/stirling/software/SPDF/EE/LicenseKeyCheckerTest.java create mode 100644 src/test/java/stirling/software/SPDF/utils/GeneralUtilsAdditionalTest.java diff --git a/src/test/java/stirling/software/SPDF/EE/LicenseKeyCheckerTest.java b/src/test/java/stirling/software/SPDF/EE/LicenseKeyCheckerTest.java new file mode 100644 index 000000000..90754ee04 --- /dev/null +++ b/src/test/java/stirling/software/SPDF/EE/LicenseKeyCheckerTest.java @@ -0,0 +1,77 @@ +package stirling.software.SPDF.EE; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import stirling.software.SPDF.EE.KeygenLicenseVerifier.License; +import stirling.software.SPDF.model.ApplicationProperties; + +@ExtendWith(MockitoExtension.class) +class LicenseKeyCheckerTest { + + @Mock private KeygenLicenseVerifier verifier; + + @Test + void premiumDisabled_skipsVerification() { + ApplicationProperties props = new ApplicationProperties(); + props.getPremium().setEnabled(false); + props.getPremium().setKey("dummy"); + + LicenseKeyChecker checker = new LicenseKeyChecker(verifier, props); + + assertEquals(License.NORMAL, checker.getPremiumLicenseEnabledResult()); + verifyNoInteractions(verifier); + } + + @Test + void directKey_verified() { + ApplicationProperties props = new ApplicationProperties(); + props.getPremium().setEnabled(true); + props.getPremium().setKey("abc"); + when(verifier.verifyLicense("abc")).thenReturn(License.PRO); + + LicenseKeyChecker checker = new LicenseKeyChecker(verifier, props); + + assertEquals(License.PRO, checker.getPremiumLicenseEnabledResult()); + verify(verifier).verifyLicense("abc"); + } + + @Test + void fileKey_verified(@TempDir Path temp) throws IOException { + Path file = temp.resolve("license.txt"); + Files.writeString(file, "filekey"); + + ApplicationProperties props = new ApplicationProperties(); + props.getPremium().setEnabled(true); + props.getPremium().setKey("file:" + file.toString()); + when(verifier.verifyLicense("filekey")).thenReturn(License.ENTERPRISE); + + LicenseKeyChecker checker = new LicenseKeyChecker(verifier, props); + + assertEquals(License.ENTERPRISE, checker.getPremiumLicenseEnabledResult()); + verify(verifier).verifyLicense("filekey"); + } + + @Test + void missingFile_resultsNormal(@TempDir Path temp) { + Path file = temp.resolve("missing.txt"); + ApplicationProperties props = new ApplicationProperties(); + props.getPremium().setEnabled(true); + props.getPremium().setKey("file:" + file.toString()); + + LicenseKeyChecker checker = new LicenseKeyChecker(verifier, props); + + assertEquals(License.NORMAL, checker.getPremiumLicenseEnabledResult()); + verifyNoInteractions(verifier); + } +} diff --git a/src/test/java/stirling/software/SPDF/utils/GeneralUtilsAdditionalTest.java b/src/test/java/stirling/software/SPDF/utils/GeneralUtilsAdditionalTest.java new file mode 100644 index 000000000..4a48cdb0f --- /dev/null +++ b/src/test/java/stirling/software/SPDF/utils/GeneralUtilsAdditionalTest.java @@ -0,0 +1,41 @@ +package stirling.software.SPDF.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class GeneralUtilsAdditionalTest { + + @Test + void testConvertSizeToBytes() { + assertEquals(1024L, GeneralUtils.convertSizeToBytes("1KB")); + assertEquals(1024L * 1024, GeneralUtils.convertSizeToBytes("1MB")); + assertEquals(1024L * 1024 * 1024, GeneralUtils.convertSizeToBytes("1GB")); + assertEquals(100L * 1024 * 1024, GeneralUtils.convertSizeToBytes("100")); + assertNull(GeneralUtils.convertSizeToBytes("invalid")); + assertNull(GeneralUtils.convertSizeToBytes(null)); + } + + @Test + void testFormatBytes() { + assertEquals("512 B", GeneralUtils.formatBytes(512)); + assertEquals("1.00 KB", GeneralUtils.formatBytes(1024)); + assertEquals("1.00 MB", GeneralUtils.formatBytes(1024L * 1024)); + assertEquals("1.00 GB", GeneralUtils.formatBytes(1024L * 1024 * 1024)); + } + + @Test + void testURLHelpersAndUUID() { + assertTrue(GeneralUtils.isValidURL("https://example.com")); + assertFalse(GeneralUtils.isValidURL("htp:/bad")); + assertFalse(GeneralUtils.isURLReachable("http://localhost")); + assertFalse(GeneralUtils.isURLReachable("ftp://example.com")); + + assertTrue(GeneralUtils.isValidUUID("123e4567-e89b-12d3-a456-426614174000")); + assertFalse(GeneralUtils.isValidUUID("not-a-uuid")); + + assertFalse(GeneralUtils.isVersionHigher(null, "1.0")); + assertTrue(GeneralUtils.isVersionHigher("2.0", "1.9")); + assertFalse(GeneralUtils.isVersionHigher("1.0", "1.0.1")); + } +} diff --git a/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java b/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java index a03564ee9..b8994faee 100644 --- a/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java +++ b/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java @@ -5,12 +5,17 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDRectangle; @@ -18,6 +23,10 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.service.CustomPDFDocumentFactory; +import stirling.software.SPDF.service.PdfMetadataService; + public class PdfUtilsTest { @Test @@ -49,4 +58,68 @@ public class PdfUtilsTest { assertTrue(PdfUtils.hasImagesOnPage(page)); } + + @Test + void testPageCountComparators() throws Exception { + PDDocument doc1 = new PDDocument(); + doc1.addPage(new PDPage()); + doc1.addPage(new PDPage()); + doc1.addPage(new PDPage()); + PdfUtils utils = new PdfUtils(); + assertTrue(utils.pageCount(doc1, 2, "greater")); + + PDDocument doc2 = new PDDocument(); + doc2.addPage(new PDPage()); + doc2.addPage(new PDPage()); + doc2.addPage(new PDPage()); + assertTrue(utils.pageCount(doc2, 3, "equal")); + + PDDocument doc3 = new PDDocument(); + doc3.addPage(new PDPage()); + doc3.addPage(new PDPage()); + assertTrue(utils.pageCount(doc3, 5, "less")); + + PDDocument doc4 = new PDDocument(); + doc4.addPage(new PDPage()); + assertThrows(IllegalArgumentException.class, () -> utils.pageCount(doc4, 1, "bad")); + } + + @Test + void testPageSize() throws Exception { + PDDocument doc = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + doc.addPage(page); + PDRectangle rect = page.getMediaBox(); + String expected = rect.getWidth() + "x" + rect.getHeight(); + PdfUtils utils = new PdfUtils(); + assertTrue(utils.pageSize(doc, expected)); + } + + @Test + void testOverlayImage() throws Exception { + PDDocument doc = new PDDocument(); + doc.addPage(new PDPage(PDRectangle.A4)); + ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); + doc.save(pdfOut); + doc.close(); + + BufferedImage image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + g.setColor(Color.RED); + g.fillRect(0, 0, 10, 10); + g.dispose(); + ByteArrayOutputStream imgOut = new ByteArrayOutputStream(); + javax.imageio.ImageIO.write(image, "png", imgOut); + + PdfMetadataService meta = + new PdfMetadataService(new ApplicationProperties(), "label", false, null); + CustomPDFDocumentFactory factory = new CustomPDFDocumentFactory(meta); + + byte[] result = + PdfUtils.overlayImage( + factory, pdfOut.toByteArray(), imgOut.toByteArray(), 0, 0, false); + try (PDDocument resultDoc = factory.load(result)) { + assertEquals(1, resultDoc.getNumberOfPages()); + } + } } From bef86b44e48e7f8a7e1dc1f83faf3e17dc624aef Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 12:07:03 +0100 Subject: [PATCH 16/17] Update 3rd Party Licenses (#3559) Auto-generated by StirlingBot Signed-off-by: stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com> Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> --- src/main/resources/static/3rdPartyLicenses.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/static/3rdPartyLicenses.json b/src/main/resources/static/3rdPartyLicenses.json index e8f6942a9..b701c302f 100644 --- a/src/main/resources/static/3rdPartyLicenses.json +++ b/src/main/resources/static/3rdPartyLicenses.json @@ -553,7 +553,7 @@ { "moduleName": "io.micrometer:micrometer-core", "moduleUrl": "https://github.com/micrometer-metrics/micrometer", - "moduleVersion": "1.14.7", + "moduleVersion": "1.15.0", "moduleLicense": "The Apache Software License, Version 2.0", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -1637,7 +1637,7 @@ { "moduleName": "org.springframework.security:spring-security-saml2-service-provider", "moduleUrl": "https://spring.io/projects/spring-security", - "moduleVersion": "6.4.5", + "moduleVersion": "6.5.0", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, @@ -1714,7 +1714,7 @@ { "moduleName": "org.springframework:spring-jdbc", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.6", + "moduleVersion": "6.2.7", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, @@ -1742,7 +1742,7 @@ { "moduleName": "org.springframework:spring-webmvc", "moduleUrl": "https://github.com/spring-projects/spring-framework", - "moduleVersion": "6.2.6", + "moduleVersion": "6.2.7", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, From 70349fb7e32551b0afa9ba8c5ae3d85bfcc30e48 Mon Sep 17 00:00:00 2001 From: Reece Browne <74901996+reecebrowne@users.noreply.github.com> Date: Tue, 20 May 2025 12:08:20 +0100 Subject: [PATCH 17/17] remove legacy homepage (#3518) # Description of Changes Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details. --- .../controller/web/HomeWebController.java | 5 +- src/main/resources/static/css/home-legacy.css | 229 -------- src/main/resources/static/js/favourites.js | 6 +- .../resources/static/js/homecard-legacy.js | 266 --------- src/main/resources/static/js/pages/home.js | 4 - .../fragments/featureGroupHeaderLegacy.html | 6 - src/main/resources/templates/home-legacy.html | 528 ------------------ src/main/resources/templates/home.html | 7 - 8 files changed, 3 insertions(+), 1048 deletions(-) delete mode 100644 src/main/resources/static/css/home-legacy.css delete mode 100644 src/main/resources/static/js/homecard-legacy.js delete mode 100644 src/main/resources/templates/fragments/featureGroupHeaderLegacy.html delete mode 100644 src/main/resources/templates/home-legacy.html diff --git a/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java b/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java index 9a3b2b3e2..9fc644863 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/HomeWebController.java @@ -77,9 +77,8 @@ public class HomeWebController { } @GetMapping("/home-legacy") - public String homeLegacy(Model model) { - model.addAttribute("currentPage", "home-legacy"); - return "home-legacy"; + public String redirectHomeLegacy() { + return "redirect:/"; } @GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/src/main/resources/static/css/home-legacy.css b/src/main/resources/static/css/home-legacy.css deleted file mode 100644 index b25fafc17..000000000 --- a/src/main/resources/static/css/home-legacy.css +++ /dev/null @@ -1,229 +0,0 @@ -#searchBar { - color: var(--md-sys-color-on-surface); - background-color: var(--md-sys-color-surface-container-low); - width: 100%; - font-size: 16px; - margin-bottom: 2rem; - padding: 0.75rem 3.5rem; - border: 1px solid var(--md-sys-color-outline-variant); - border-radius: 3rem; - outline-color: var(--md-sys-color-outline-variant); - } - - #filtersContainer { - display: flex; - width: 100%; - align-items: center; - justify-content: center; - gap: 10px; - } - - .filter-button { - color: var(--md-sys-color-secondary); - user-select: none; - cursor: pointer; - transition: transform 0.3s; - transform-origin: center center; - } - - .filter-button:hover { - transform: scale(1.08); - } - - .search-icon { - position: absolute; - margin: 0.75rem 1rem; - border: 0.1rem solid transparent; - } - - .features-container { - display: flex; - flex-direction: column; - gap: 30px; - } - - .feature-group-legacy { - display: flex; - flex-direction: column; - } - - .feature-group-header { - display: flex; - align-items: center; - justify-content: flex-start; - color: var(--md-sys-color-on-surface); - margin-bottom: 15px; - user-select: none; - cursor: pointer; - gap: 10px; - } - - .feature-group-container { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr)); - gap: 30px 30px; - overflow: hidden; - margin: -20px; - padding: 20px; - box-sizing:content-box; - } - - .feature-group-container.animated-group { - transition: 0.5s all; - } - - .feature-group-legacy.collapsed>.feature-group-container { - max-height: 0 !important; - margin: 0; - padding: 0; - } - - .header-expand-button { - transition: 0.5s all; - transform: rotate(90deg); - } - - .header-expand-button.collapsed { - transform: rotate(0deg); - } - - .feature-card { - border: 1px solid var(--md-sys-color-surface-5); - border-radius: 1.75rem; - padding: 1.25rem; - display: flex; - flex-direction: column; - align-items: flex-start; - background: var(--md-sys-color-surface-5); - transition: - transform 0.3s, - border 0.3s; - transform-origin: center center; - outline: 0px solid transparent; - position:relative; - } - - .feature-card a { - text-decoration: none; - color: var(--md-sys-color-on-surface); - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - } - - .feature-card .card-text { - font-size: .875rem; - } - - .feature-card:hover { - cursor: pointer; - transform: scale(1.08); - box-shadow: var(--md-sys-elevation-2); - } - - .card-title.text-primary { - color: #000; - } - - .home-card-icon { - width: 3rem; - height: 3rem; - transform: translateY(-5px); - } - - .favorite-icon { - display: none !important; - position: absolute; - top: 10px; - right: 10px; - color: var(--md-sys-color-secondary); - } - - #tool-icon { - height: 100%; - } - - #tool-text { - margin: 0.0rem 0 0 1.25rem; - } - - .card-title { - margin-bottom: 1rem; - font-size: 1.1rem; - } - - /* Only show the favorite icons when the parent card is being hovered over */ - .feature-card:hover .favorite-icon { - display: block !important; - } - - .favorite-icon img { - filter: brightness(0) invert(var(--md-theme-filter-color)); - } - - .favorite-icon:hover .material-symbols-rounded { - transform: scale(1.2); - } - - .favorite-icon .material-symbols-rounded.fill{ - color: #f5c000; - } - - .jumbotron { - padding: 3rem 3rem; - /* Reduce vertical padding */ - } - - .lookatme { - opacity: 1; - position: relative; - display: inline-block; - } - - .lookatme::after { - color: #e33100; - text-shadow: 0 0 5px #e33100; - /* in the html, the data-lookatme-text attribute must */ - /* contain the same text as the .lookatme element */ - content: attr(data-lookatme-text); - padding: inherit; - position: absolute; - inset: 0 0 0 0; - z-index: 1; - /* 20 steps / 2 seconds = 10fps */ - -webkit-animation: 2s infinite Pulse steps(20); - animation: 2s infinite Pulse steps(20); - } - - @keyframes Pulse { - from { - opacity: 0; - } - - 50% { - opacity: 1; - } - - to { - opacity: 0; - } - } - - .update-notice { - animation: scale 1s infinite alternate; - } - - @keyframes scale { - 0% { - transform: scale(0.96); - } - - 100% { - transform: scale(1); - } - } - - .hidden { - visibility: hidden; - } diff --git a/src/main/resources/static/js/favourites.js b/src/main/resources/static/js/favourites.js index 913c656b2..5aab52824 100644 --- a/src/main/resources/static/js/favourites.js +++ b/src/main/resources/static/js/favourites.js @@ -126,11 +126,7 @@ function addToFavorites(entryId) { localStorage.setItem('favoritesList', JSON.stringify(favoritesList)); updateFavoritesDropdown(); updateFavoriteIcons(); - const currentPath = window.location.pathname; - if (currentPath.includes('home-legacy')) { - syncFavoritesLegacy(); - } else { + initializeCards(); - } } } diff --git a/src/main/resources/static/js/homecard-legacy.js b/src/main/resources/static/js/homecard-legacy.js deleted file mode 100644 index a43453f1c..000000000 --- a/src/main/resources/static/js/homecard-legacy.js +++ /dev/null @@ -1,266 +0,0 @@ -function filterCardsLegacy() { - var input = document.getElementById('searchBar'); - var filter = input.value.toUpperCase(); - - let featureGroups = document.querySelectorAll('.feature-group-legacy'); - const collapsedGroups = getCollapsedGroups(); - - for (const featureGroup of featureGroups) { - var cards = featureGroup.querySelectorAll('.feature-card'); - - let groupMatchesFilter = false; - for (var i = 0; i < cards.length; i++) { - var card = cards[i]; - var title = card.querySelector('h5.card-title').innerText; - var text = card.querySelector('p.card-text').innerText; - - // Get the navbar tags associated with the card - var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`); - var navbarTags = navbarItem ? navbarItem.getAttribute('data-bs-tags') : ''; - - var content = title + ' ' + text + ' ' + navbarTags; - - if (content.toUpperCase().indexOf(filter) > -1) { - card.style.display = ''; - groupMatchesFilter = true; - } else { - card.style.display = 'none'; - } - } - - if (!groupMatchesFilter) { - featureGroup.style.display = 'none'; - } else { - featureGroup.style.display = ''; - resetOrTemporarilyExpandGroup(featureGroup, filter, collapsedGroups); - } - } -} - -function getCollapsedGroups() { - return localStorage.getItem('collapsedGroups') ? JSON.parse(localStorage.getItem('collapsedGroups')) : []; -} - -function resetOrTemporarilyExpandGroup(featureGroup, filterKeywords = '', collapsedGroups = []) { - const shouldResetCollapse = filterKeywords.trim() === ''; - if (shouldResetCollapse) { - // Resetting the group's expand/collapse to its original state (as in collapsed groups) - const isCollapsed = collapsedGroups.indexOf(featureGroup.id) != -1; - expandCollapseToggle(featureGroup, !isCollapsed); - } else { - // Temporarily expands feature group without affecting the actual/stored collapsed groups - featureGroup.classList.remove('collapsed'); - featureGroup.querySelector('.header-expand-button').classList.remove('collapsed'); - } -} - -function updateFavoritesSectionLegacy() { - const favoritesContainer = document.getElementById('groupFavorites').querySelector('.feature-group-container'); - favoritesContainer.innerHTML = ''; - const cards = Array.from(document.querySelectorAll('.feature-card:not(.duplicate)')); - const addedCardIds = new Set(); - let favoritesAmount = 0; - - cards.forEach((card) => { - const favouritesList = JSON.parse(localStorage.getItem('favoritesList') || '[]'); - - if (favouritesList.includes(card.id) && !addedCardIds.has(card.id)) { - const duplicate = card.cloneNode(true); - duplicate.classList.add('duplicate'); - favoritesContainer.appendChild(duplicate); - addedCardIds.add(card.id); - favoritesAmount++; - } - }); - - if (favoritesAmount === 0) { - document.getElementById('groupFavorites').style.display = 'none'; - } else { - document.getElementById('groupFavorites').style.display = 'flex'; - } - reorderCards(favoritesContainer); -} - -function syncFavoritesLegacy() { - const cards = Array.from(document.querySelectorAll('.feature-card')); - cards.forEach((card) => { - const isFavorite = localStorage.getItem(card.id) === 'favorite'; - const starIcon = card.querySelector('.favorite-icon span.material-symbols-rounded'); - if (starIcon) { - if (isFavorite) { - starIcon.classList.remove('no-fill'); - starIcon.classList.add('fill'); - card.classList.add('favorite'); - } else { - starIcon.classList.remove('fill'); - starIcon.classList.add('no-fill'); - card.classList.remove('favorite'); - } - } - }); - updateFavoritesSectionLegacy(); - updateFavoritesDropdown(); - filterCardsLegacy(); -} - -function reorderCards(container) { - var cards = Array.from(container.querySelectorAll('.feature-card')); - cards.forEach(function (card) { - container.removeChild(card); - }); - cards.sort(function (a, b) { - var aIsFavorite = localStorage.getItem(a.id) === 'favorite'; - var bIsFavorite = localStorage.getItem(b.id) === 'favorite'; - if (a.id === 'update-link') { - return -1; - } - if (b.id === 'update-link') { - return 1; - } - - if (aIsFavorite && !bIsFavorite) { - return -1; - } else if (!aIsFavorite && bIsFavorite) { - return 1; - } else { - return a.id > b.id; - } - }); - cards.forEach(function (card) { - container.appendChild(card); - }); -} - -function reorderAllCards() { - const containers = Array.from(document.querySelectorAll('.feature-group-container')); - containers.forEach(function (container) { - reorderCards(container); - }); -} - -function initializeCardsLegacy() { - reorderAllCards(); - updateFavoritesSectionLegacy(); - updateFavoritesDropdown(); - filterCardsLegacy(); -} - -function showFavoritesOnly() { - const groups = Array.from(document.querySelectorAll('.feature-group-legacy')); - if (localStorage.getItem('favoritesOnly') === 'true') { - groups.forEach((group) => { - if (group.id !== 'groupFavorites') { - group.style.display = 'none'; - } - }); - } else { - groups.forEach((group) => { - if (group.id !== 'groupFavorites') { - group.style.display = 'flex'; - } - }); - } -} - -function toggleFavoritesOnly() { - if (localStorage.getItem('favoritesOnly') === 'true') { - localStorage.setItem('favoritesOnly', 'false'); - } else { - localStorage.setItem('favoritesOnly', 'true'); - } - showFavoritesOnly(); -} - -// Expands a feature group on true, collapses it on false and toggles state on null. -function expandCollapseToggle(group, expand = null) { - if (expand === null) { - group.classList.toggle('collapsed'); - group.querySelector('.header-expand-button').classList.toggle('collapsed'); - } else if (expand) { - group.classList.remove('collapsed'); - group.querySelector('.header-expand-button').classList.remove('collapsed'); - } else { - group.classList.add('collapsed'); - group.querySelector('.header-expand-button').classList.add('collapsed'); - } - - const collapsed = localStorage.getItem('collapsedGroups') ? JSON.parse(localStorage.getItem('collapsedGroups')) : []; - const groupIndex = collapsed.indexOf(group.id); - - if (group.classList.contains('collapsed')) { - if (groupIndex === -1) { - collapsed.push(group.id); - } - } else { - if (groupIndex !== -1) { - collapsed.splice(groupIndex, 1); - } - } - - localStorage.setItem('collapsedGroups', JSON.stringify(collapsed)); -} - -function expandCollapseAll(expandAll) { - const groups = Array.from(document.querySelectorAll('.feature-group-legacy')); - groups.forEach((group) => { - expandCollapseToggle(group, expandAll); - }); -} - -window.onload = function () { - initializeCardsLegacy(); - syncFavoritesLegacy(); // Ensure everything is in sync on page load -}; - -document.addEventListener('DOMContentLoaded', function () { - const materialIcons = new FontFaceObserver('Material Symbols Rounded'); - - materialIcons - .load() - .then(() => { - document.querySelectorAll('.feature-card.hidden').forEach((el) => { - el.classList.remove('hidden'); - }); - }) - .catch(() => { - console.error('Material Symbols Rounded font failed to load.'); - }); - - Array.from(document.querySelectorAll('.feature-group-header-legacy')).forEach((header) => { - const parent = header.parentNode; - const container = header.parentNode.querySelector('.feature-group-container'); - if (parent.id !== 'groupFavorites') { - // container.style.maxHeight = container.scrollHeight + 'px'; - } - header.onclick = () => { - expandCollapseToggle(parent); - }; - }); - - const collapsed = localStorage.getItem('collapsedGroups') ? JSON.parse(localStorage.getItem('collapsedGroups')) : []; - const groupsArray = Array.from(document.querySelectorAll('.feature-group-legacy')); - - groupsArray.forEach((group) => { - if (collapsed.indexOf(group.id) !== -1) { - expandCollapseToggle(group, false); - } - }); - - // Necessary in order to not fire the transition animation on page load, which looks wrong. - // The timeout isn't doing anything visible to the user, so it's not making the page load look slower. - setTimeout(() => { - groupsArray.forEach((group) => { - const container = group.querySelector('.feature-group-container'); - container.classList.add('animated-group'); - }); - }, 500); - - Array.from(document.querySelectorAll('.feature-group-header')).forEach((header) => { - const parent = header.parentNode; - header.onclick = () => { - expandCollapseToggle(parent); - }; - }); - - showFavoritesOnly(); -}); diff --git a/src/main/resources/static/js/pages/home.js b/src/main/resources/static/js/pages/home.js index bb1e1ad4a..d474e9439 100644 --- a/src/main/resources/static/js/pages/home.js +++ b/src/main/resources/static/js/pages/home.js @@ -55,10 +55,6 @@ hideCookieBanner(); updateFavoriteIcons(); const contentPath = /*[[${@contextPath}]]*/ ''; -const defaultView = localStorage.getItem('defaultView') || 'home'; // Default to "home" -if (defaultView === 'home-legacy') { - window.location.href = contentPath + 'home-legacy'; // Redirect to legacy view -} document.addEventListener('DOMContentLoaded', function () { const surveyVersion = '3.0'; diff --git a/src/main/resources/templates/fragments/featureGroupHeaderLegacy.html b/src/main/resources/templates/fragments/featureGroupHeaderLegacy.html deleted file mode 100644 index 0a8f7e9b1..000000000 --- a/src/main/resources/templates/fragments/featureGroupHeaderLegacy.html +++ /dev/null @@ -1,6 +0,0 @@ -
          - - - chevron_right - -
          \ No newline at end of file diff --git a/src/main/resources/templates/home-legacy.html b/src/main/resources/templates/home-legacy.html deleted file mode 100644 index d60ac220e..000000000 --- a/src/main/resources/templates/home-legacy.html +++ /dev/null @@ -1,528 +0,0 @@ - - - - - - - - -
          -
          - - -
          -
          -

          -

          -

          -
          -
          -
          - - -
          -
          - - search - - - -
          - - star - - - expand_all - - - collapse_all - - -
          - -
          - - - -
          -
          -
          -
          -
          -
          - - -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          - - - - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index a7cbbbd80..0bb9a2c06 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -82,13 +82,6 @@ visibility
      - - - home - -