From e239bbf89a130d759f1fba11ab38634a34914778 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 14:31:44 +0100 Subject: [PATCH 01/15] Bump github/codeql-action from 3.28.16 to 3.28.17 (#3467) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.16 to 3.28.17.
Release notes

Sourced from github/codeql-action's releases.

v3.28.17

CodeQL Action Changelog

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

3.28.17 - 02 May 2025

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.17 - 02 May 2025

3.28.16 - 23 Apr 2025

3.28.15 - 07 Apr 2025

3.28.14 - 07 Apr 2025

3.28.13 - 24 Mar 2025

No user facing changes.

3.28.12 - 19 Mar 2025

3.28.11 - 07 Mar 2025

3.28.10 - 21 Feb 2025

3.28.9 - 07 Feb 2025

3.28.8 - 29 Jan 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.16&new-version=3.28.17)](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 327257e3f..3c2d59e3e 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@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 + uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17 with: sarif_file: results.sarif From 561d3f4eed99f8a60f019916d13781a4cac0b51b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 14:31:49 +0100 Subject: [PATCH 02/15] Bump actions/create-github-app-token from 2.0.2 to 2.0.5 (#3466) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.0.2 to 2.0.5.
Release notes

Sourced from actions/create-github-app-token's releases.

v2.0.5

2.0.5 (2025-05-02)

Bug Fixes

  • deps: bump the production-dependencies group with 3 updates (#240) (d64d7d7)

v2.0.4

2.0.4 (2025-05-02)

Bug Fixes

v2.0.3

2.0.3 (2025-05-01)

Bug Fixes

  • README: use v2 in examples (#234) (9ba274d), closes #232
  • use core.getBooleanInput() to retrieve boolean input values (#223) (c3c17c7)
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=2.0.2&new-version=2.0.5)](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 | 4 ++-- .github/workflows/licenses-update.yml | 2 +- .github/workflows/pre_commit.yml | 2 +- .github/workflows/sync_files.yml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index 64cecea71..291e6b97a 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -48,7 +48,7 @@ jobs: # Generate GitHub App token - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -135,7 +135,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index 0851b1490..e05c4b40f 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -24,7 +24,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml index 6e3bacd42..3c121da17 100644 --- a/.github/workflows/pre_commit.yml +++ b/.github/workflows/pre_commit.yml @@ -22,7 +22,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/sync_files.yml b/.github/workflows/sync_files.yml index fdac87028..a9c72d5f0 100644 --- a/.github/workflows/sync_files.yml +++ b/.github/workflows/sync_files.yml @@ -30,7 +30,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -63,7 +63,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 with: app-id: ${{ vars.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} From 20f0cf1ac355769a6ccdc8db0b2f6942482bc1e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 May 2025 14:32:08 +0100 Subject: [PATCH 03/15] Bump pdfboxVersion from 3.0.4 to 3.0.5 (#3465) Bumps `pdfboxVersion` from 3.0.4 to 3.0.5. Updates `org.apache.pdfbox:pdfbox` from 3.0.4 to 3.0.5 Updates `org.apache.pdfbox:preflight` from 3.0.4 to 3.0.5 Updates `org.apache.pdfbox:xmpbox` from 3.0.4 to 3.0.5 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 c872be274..1162952d9 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ import java.time.Year ext { springBootVersion = "3.4.5" - pdfboxVersion = "3.0.4" + pdfboxVersion = "3.0.5" imageioVersion = "3.12.0" lombokVersion = "1.18.38" bouncycastleVersion = "1.80" From 294724659d199d732a19ffbabf773922f3de6cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sz=C3=BCcs?= <127139797+Balazs-Szucs@users.noreply.github.com> Date: Sat, 3 May 2025 15:34:41 +0200 Subject: [PATCH 04/15] Update language list to use native names (#3464) # Description of Changes: This PR updates the localization files to use the correct native names for affected languages, ensuring consistency and proper representation For the translation I didn't know I searched and subsequently, and verified with Gemini that the translation is valid. For example: ## Hungarian -> Magyar ![image](https://github.com/user-attachments/assets/177f4e85-fbb9-4486-9708-08679597ef08) --- ## Checklist ### General - [x] 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) - [x] I have performed a self-review of my own code - [x] 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) - [x] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [x] 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. --- .../resources/templates/fragments/languages.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/templates/fragments/languages.html b/src/main/resources/templates/fragments/languages.html index 939e5ad6f..3a01449c9 100644 --- a/src/main/resources/templates/fragments/languages.html +++ b/src/main/resources/templates/fragments/languages.html @@ -13,24 +13,24 @@
-
-
+
+
-
-
-
+
+
+
-
+
From 5ca956f03354c8ae547a7e0f6179396b28f9ee53 Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Sun, 4 May 2025 17:19:50 +0100 Subject: [PATCH 05/15] Update 3rd Party Licenses (#3468) 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 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/static/3rdPartyLicenses.json b/src/main/resources/static/3rdPartyLicenses.json index 4d1c7bfb5..c20671d97 100644 --- a/src/main/resources/static/3rdPartyLicenses.json +++ b/src/main/resources/static/3rdPartyLicenses.json @@ -871,7 +871,7 @@ { "moduleName": "org.apache.pdfbox:fontbox", "moduleUrl": "https://pdfbox.apache.org", - "moduleVersion": "3.0.4", + "moduleVersion": "3.0.5", "moduleLicense": "Apache-2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -884,28 +884,28 @@ { "moduleName": "org.apache.pdfbox:pdfbox", "moduleUrl": "https://pdfbox.apache.org", - "moduleVersion": "3.0.4", + "moduleVersion": "3.0.5", "moduleLicense": "Apache-2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "org.apache.pdfbox:pdfbox-io", "moduleUrl": "https://pdfbox.apache.org", - "moduleVersion": "3.0.4", + "moduleVersion": "3.0.5", "moduleLicense": "Apache-2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "org.apache.pdfbox:preflight", "moduleUrl": "https://pdfbox.apache.org", - "moduleVersion": "3.0.4", + "moduleVersion": "3.0.5", "moduleLicense": "Apache-2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "org.apache.pdfbox:xmpbox", "moduleUrl": "https://pdfbox.apache.org", - "moduleVersion": "3.0.4", + "moduleVersion": "3.0.5", "moduleLicense": "Apache-2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, From b8aa9f0cdf94ec06f9d3a84d694795bed955e612 Mon Sep 17 00:00:00 2001 From: Ludy Date: Sun, 4 May 2025 18:20:07 +0200 Subject: [PATCH 06/15] Fix NullPointerException by Enabling Constructor Injection for Color Replacement Components (#3469) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes Please provide a summary of the changes, including: - **What was changed** Added the `final` modifier to the `ReplaceAndInvertColorService` field in `ReplaceAndInvertColorController` and to the `ReplaceAndInvertColorFactory` field in `ReplaceAndInvertColorService`. This ensures that Lombok’s `@RequiredArgsConstructor` generates constructors for these dependencies, enabling proper constructor-based injection instead of leaving them null. - **Why the change was made** Without the `final` keyword, Lombok does not include non-final fields in the generated constructor, causing Spring to leave them uninitialized and resulting in a `NullPointerException` during runtime when invoking `replaceAndInvert` on the factory/service. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] 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) - [x] I have performed a self-review of my own code - [x] 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/api/misc/ReplaceAndInvertColorController.java | 2 +- .../SPDF/service/misc/ReplaceAndInvertColorService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/ReplaceAndInvertColorController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/ReplaceAndInvertColorController.java index 927b3a51f..865724a74 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/misc/ReplaceAndInvertColorController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/misc/ReplaceAndInvertColorController.java @@ -25,7 +25,7 @@ import stirling.software.SPDF.service.misc.ReplaceAndInvertColorService; @RequiredArgsConstructor public class ReplaceAndInvertColorController { - private ReplaceAndInvertColorService replaceAndInvertColorService; + private final ReplaceAndInvertColorService replaceAndInvertColorService; @PostMapping(consumes = "multipart/form-data", value = "/replace-invert-pdf") @Operation( diff --git a/src/main/java/stirling/software/SPDF/service/misc/ReplaceAndInvertColorService.java b/src/main/java/stirling/software/SPDF/service/misc/ReplaceAndInvertColorService.java index 20c20eb7b..e2a4e7ea5 100644 --- a/src/main/java/stirling/software/SPDF/service/misc/ReplaceAndInvertColorService.java +++ b/src/main/java/stirling/software/SPDF/service/misc/ReplaceAndInvertColorService.java @@ -16,7 +16,7 @@ import stirling.software.SPDF.utils.misc.ReplaceAndInvertColorStrategy; @Service @RequiredArgsConstructor public class ReplaceAndInvertColorService { - private ReplaceAndInvertColorFactory replaceAndInvertColorFactory; + private final ReplaceAndInvertColorFactory replaceAndInvertColorFactory; public InputStreamResource replaceAndInvertColor( MultipartFile file, From 36758a6a3516930e82d23e5c3c204880441fc5fb Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 23:23:08 +0100 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=A4=96=20format=20everything=20with?= =?UTF-8?q?=20pre-commit=20by=20=20(#3479)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-generated by [create-pull-request][1] with **stirlingbot** [1]: https://github.com/peter-evans/create-pull-request Signed-off-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> --- src/main/resources/static/js/multitool/PdfContainer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index 32c34ba46..90d130b2f 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -462,7 +462,7 @@ class PdfContainer { this.showButton(selectIcon, true); this.showButton(deselectIcon, false); - + checkboxes.forEach((checkbox) => { checkbox.checked = false; @@ -583,7 +583,7 @@ class PdfContainer { const selectIcon = document.getElementById('select-All-Container'); const deselectIcon = document.getElementById('deselect-All-Container'); - + if (window.selectPage) { // Check if selectPage mode is active console.log("Page Select on. Showing buttons"); //Check if no pages are selected @@ -907,7 +907,7 @@ class PdfContainer { if (!allSelected) { this.showButton(document.getElementById('select-All-Container'), true); } - + if (window.selectedPages.length > 0) { this.showButton(document.getElementById('deselect-All-Container'), true); } From 3a615360a07b817182e1aa208d748115c1521427 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 23:23:16 +0100 Subject: [PATCH 08/15] Bump actions/create-github-app-token from 2.0.5 to 2.0.6 (#3475) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.0.5 to 2.0.6.
Release notes

Sourced from actions/create-github-app-token's releases.

v2.0.6

2.0.6 (2025-05-03)

Bug Fixes

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/create-github-app-token&package-manager=github_actions&previous-version=2.0.5&new-version=2.0.6)](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 | 4 ++-- .github/workflows/licenses-update.yml | 2 +- .github/workflows/pre_commit.yml | 2 +- .github/workflows/sync_files.yml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index 291e6b97a..adb3e33cf 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -48,7 +48,7 @@ jobs: # Generate GitHub App token - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -135,7 +135,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index e05c4b40f..f2ab49f88 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -24,7 +24,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml index 3c121da17..ce10a6c3e 100644 --- a/.github/workflows/pre_commit.yml +++ b/.github/workflows/pre_commit.yml @@ -22,7 +22,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/sync_files.yml b/.github/workflows/sync_files.yml index a9c72d5f0..fe790c65b 100644 --- a/.github/workflows/sync_files.yml +++ b/.github/workflows/sync_files.yml @@ -30,7 +30,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} @@ -63,7 +63,7 @@ jobs: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@db3cdf40984fe6fd25ae19ac2bf2f4886ae8d959 # v2.0.5 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ vars.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} From bfaffe50505d75fb9efb4ed94642a2456a0c9b39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 10:43:09 +0100 Subject: [PATCH 09/15] Bump org.springdoc:springdoc-openapi-starter-webmvc-ui from 2.8.6 to 2.8.8 (#3482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.springdoc:springdoc-openapi-starter-webmvc-ui](https://github.com/springdoc/springdoc-openapi) from 2.8.6 to 2.8.8.
Release notes

Sourced from org.springdoc:springdoc-openapi-starter-webmvc-ui's releases.

v2.8.8

Full Changelog: https://github.com/springdoc/springdoc-openapi/compare/v2.8.7...v2.8.8

Fixed

  • #2977 - Handle projects not using kotlin-reflect #2977

springdoc-openapi v2.8.7 released!

What's Changed

Added

  • #2944 - Introducing springdoc-openapi-bom project
  • #2948 - Customize Servers via application.yml
  • #2963 - Set default content type for problem details object to application/problem+jso
  • #2971 - List of value classes in Kotlin

Changed

  • Upgrade swagger-ui to v5.21.0
  • Upgrade swagger-core to 2.2.30
  • Upgrade spring-boot to version 3.4.5
  • Upgrade spring-security-oauth2-authorization-server to version 1.4.3

Fixed

  • #2947 - Unexpected warning "Appended trailing slash to static resource location"
  • #2960 - NPE when customizing group's open-api without specifying any schema
  • #2969 - fix path to register resource handler to work SwaggerIndexPageTransformer considering /webjar path prefix
  • #2964 - Cannot add custom description and example for java.time.Duration since v2.8.6
  • #2972 - @​Header(schema = @​Schema(type = "string")) generates empty or broken schema in OpenAPI output since 2.8.0
  • #2976, #2967 - Build Failure due to Private Inner Class.
  • #2556 - Unable to determine if it is a Kotlin type

New Contributors

Full Changelog: https://github.com/springdoc/springdoc-openapi/compare/v2.8.6...v2.8.7

Changelog

Sourced from org.springdoc:springdoc-openapi-starter-webmvc-ui's changelog.

[2.8.8] - 2025-05-04

Fixed

  • #2977 - Handle projects not using kotlin-reflect #2977

[2.8.7] - 2025-05-04

Added

  • #2944 - Introducing springdoc-openapi-bom project
  • #2948 - Customize Servers via application.yml
  • #2963 - Set default content type for problem details object to application/problem+jso
  • #2971 - List of value classes in Kotlin

Changed

  • Upgrade swagger-ui to v5.21.0
  • Upgrade swagger-core to 2.2.30
  • Upgrade spring-boot to version 3.4.5
  • Upgrade spring-security-oauth2-authorization-server to version 1.4.3

Fixed

  • #2947 - Unexpected warning "Appended trailing slash to static resource location"
  • #2960 - NPE when customizing group's open-api without specifying any schema
  • #2969 - fix path to register resource handler to work SwaggerIndexPageTransformer considering /webjar path prefix
  • #2964 - Cannot add custom description and example for java.time.Duration since v2.8.6
  • #2972 - @​Header(schema = @​Schema(type = "string")) generates empty or broken schema in OpenAPI output since 2.8.0
  • #2976, #2967 - Build Failure due to Private Inner Class.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springdoc:springdoc-openapi-starter-webmvc-ui&package-manager=gradle&previous-version=2.8.6&new-version=2.8.8)](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 1162952d9..a49189054 100644 --- a/build.gradle +++ b/build.gradle @@ -506,7 +506,7 @@ dependencies { implementation "com.drewnoakes:metadata-extractor:2.19.0" implementation "commons-io:commons-io:2.19.0" - implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6" + implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8" //general PDF // https://mvnrepository.com/artifact/com.opencsv/opencsv From 1aff1d3480c9f12dad3b6dc697466a3aa932a9b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 10:43:42 +0100 Subject: [PATCH 10/15] Bump com.opencsv:opencsv from 5.10 to 5.11 (#3476) 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 com.opencsv:opencsv from 5.10 to 5.11. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.opencsv:opencsv&package-manager=gradle&previous-version=5.10&new-version=5.11)](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 a49189054..76277cc99 100644 --- a/build.gradle +++ b/build.gradle @@ -510,7 +510,7 @@ dependencies { //general PDF // https://mvnrepository.com/artifact/com.opencsv/opencsv - implementation ("com.opencsv:opencsv:5.10") + implementation ("com.opencsv:opencsv:5.11") implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") implementation "org.apache.pdfbox:preflight:$pdfboxVersion" From 5d073909cc6f0a58a8e012a2a76d6ee67552a569 Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 17:53:51 +0100 Subject: [PATCH 11/15] Update 3rd Party Licenses (#3484) 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> --- .../resources/static/3rdPartyLicenses.json | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/resources/static/3rdPartyLicenses.json b/src/main/resources/static/3rdPartyLicenses.json index c20671d97..4395d1fa0 100644 --- a/src/main/resources/static/3rdPartyLicenses.json +++ b/src/main/resources/static/3rdPartyLicenses.json @@ -270,7 +270,7 @@ { "moduleName": "com.opencsv:opencsv", "moduleUrl": "http://opencsv.sf.net", - "moduleVersion": "5.10", + "moduleVersion": "5.11", "moduleLicense": "Apache 2", "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -623,21 +623,21 @@ { "moduleName": "io.swagger.core.v3:swagger-annotations-jakarta", "moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-annotations", - "moduleVersion": "2.2.29", + "moduleVersion": "2.2.30", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "io.swagger.core.v3:swagger-core-jakarta", "moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-core", - "moduleVersion": "2.2.29", + "moduleVersion": "2.2.30", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, { "moduleName": "io.swagger.core.v3:swagger-models-jakarta", "moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-models", - "moduleVersion": "2.2.29", + "moduleVersion": "2.2.30", "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, @@ -1235,6 +1235,12 @@ "moduleLicense": "GNU Library General Public License v2.1 or later", "moduleLicenseUrl": "https://www.opensource.org/licenses/LGPL-2.1" }, + { + "moduleName": "org.hibernate.validator:hibernate-validator", + "moduleVersion": "8.0.2.Final", + "moduleLicense": "Apache License 2.0", + "moduleLicenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.txt" + }, { "moduleName": "org.jboss.logging:jboss-logging", "moduleUrl": "http://www.jboss.org", @@ -1423,19 +1429,19 @@ }, { "moduleName": "org.springdoc:springdoc-openapi-starter-common", - "moduleVersion": "2.8.6", + "moduleVersion": "2.8.8", "moduleLicense": "The Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "org.springdoc:springdoc-openapi-starter-webmvc-api", - "moduleVersion": "2.8.6", + "moduleVersion": "2.8.8", "moduleLicense": "The Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, { "moduleName": "org.springdoc:springdoc-openapi-starter-webmvc-ui", - "moduleVersion": "2.8.6", + "moduleVersion": "2.8.8", "moduleLicense": "The Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0.txt" }, @@ -1544,6 +1550,13 @@ "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, + { + "moduleName": "org.springframework.boot:spring-boot-starter-validation", + "moduleUrl": "https://spring.io/projects/spring-boot", + "moduleVersion": "3.4.5", + "moduleLicense": "Apache License, Version 2.0", + "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" + }, { "moduleName": "org.springframework.boot:spring-boot-starter-web", "moduleUrl": "https://spring.io/projects/spring-boot", @@ -1746,7 +1759,7 @@ { "moduleName": "org.webjars:swagger-ui", "moduleUrl": "https://www.webjars.org", - "moduleVersion": "5.20.1", + "moduleVersion": "5.21.0", "moduleLicense": "Apache-2.0" }, { From e2a5874a887a7ca895b59ce70d2b5d26913257d4 Mon Sep 17 00:00:00 2001 From: Ludy Date: Wed, 7 May 2025 10:18:02 +0200 Subject: [PATCH 12/15] fix read wrong properties (#3472) # Description of Changes Please provide a summary of the changes, including: Test file: [12345678.pdf](https://github.com/user-attachments/files/20028981/12345678.pdf) Behavior without readOnly ```json { "creator": null, "modificationDate": "java.util.GregorianCalendar[time=1746381303000,areFieldsSet=true,areAllFieldsSet=true,lenient=false,zone=java.util.SimpleTimeZone[id=GMT,offset=0,dstSavings=3600000,useDaylight=false,startYear=0,startMode=0,startMonth=0,startDay=0,startDayOfWeek=0,startTime=0,startTimeMode=0,endMode=0,endMonth=0,endDay=0,endDayOfWeek=0,endTime=0,endTimeMode=0],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2025,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=4,DAY_OF_YEAR=124,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=55,SECOND=3,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]", "keywords": null, "author": "", "subject": null, "producer": "Stirling-PDF v0.46.0", "title": "Microsoft Word - Dokument1", "creationDate": "java.util.GregorianCalendar[time=1746381238000,areFieldsSet=true,areAllFieldsSet=true,lenient=false,zone=java.util.SimpleTimeZone[id=GMT+02:00,offset=7200000,dstSavings=3600000,useDaylight=false,startYear=0,startMode=0,startMonth=0,startDay=0,startDayOfWeek=0,startTime=0,startTimeMode=0,endMode=0,endMonth=0,endDay=0,endDayOfWeek=0,endTime=0,endTimeMode=0],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2025,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=4,DAY_OF_YEAR=124,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=53,SECOND=58,MILLISECOND=0,ZONE_OFFSET=7200000,DST_OFFSET=0]" } ``` with readOnly=true ```json { "creator": null, "modificationDate": "java.util.GregorianCalendar[time=1746381238000,areFieldsSet=true,areAllFieldsSet=true,lenient=false,zone=java.util.SimpleTimeZone[id=GMT+02:00,offset=7200000,dstSavings=3600000,useDaylight=false,startYear=0,startMode=0,startMonth=0,startDay=0,startDayOfWeek=0,startTime=0,startTimeMode=0,endMode=0,endMonth=0,endDay=0,endDayOfWeek=0,endTime=0,endTimeMode=0],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2025,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=4,DAY_OF_YEAR=124,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=53,SECOND=58,MILLISECOND=0,ZONE_OFFSET=7200000,DST_OFFSET=0]", "keywords": null, "author": "", "subject": null, "producer": "Microsoft: Print To PDF", "title": "Microsoft Word - Dokument1", "creationDate": "java.util.GregorianCalendar[time=1746381238000,areFieldsSet=true,areAllFieldsSet=true,lenient=false,zone=java.util.SimpleTimeZone[id=GMT+02:00,offset=7200000,dstSavings=3600000,useDaylight=false,startYear=0,startMode=0,startMonth=0,startDay=0,startDayOfWeek=0,startTime=0,startTimeMode=0,endMode=0,endMonth=0,endDay=0,endDayOfWeek=0,endTime=0,endTimeMode=0],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2025,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=4,DAY_OF_YEAR=124,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=7,HOUR_OF_DAY=19,MINUTE=53,SECOND=58,MILLISECOND=0,ZONE_OFFSET=7200000,DST_OFFSET=0]" } ``` --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] 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) - [x] I have performed a self-review of my own code - [x] 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. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../software/SPDF/controller/api/AnalysisController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/stirling/software/SPDF/controller/api/AnalysisController.java b/src/main/java/stirling/software/SPDF/controller/api/AnalysisController.java index 75f61e64e..49c5bc81c 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/AnalysisController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/AnalysisController.java @@ -59,7 +59,8 @@ public class AnalysisController { description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO") public Map getDocumentProperties(@ModelAttribute PDFFile file) throws IOException { - try (PDDocument document = pdfDocumentFactory.load(file.getFileInput())) { + // Load the document in read-only mode to prevent modifications and ensure the integrity of the original file. + try (PDDocument document = pdfDocumentFactory.load(file.getFileInput(), true)) { PDDocumentInformation info = document.getDocumentInformation(); Map properties = new HashMap<>(); properties.put("title", info.getTitle()); From 2ac606608aa545f83c78b8baf95626cdf18c2536 Mon Sep 17 00:00:00 2001 From: Ludy Date: Wed, 7 May 2025 10:19:06 +0200 Subject: [PATCH 13/15] Fix cert-sign API NullPointerException when pageNumber is omitted for invisible signatures (#3463) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes Please provide a summary of the changes, including: - **What was changed** - Updated `SignPDFWithCertRequest` to use `Boolean` for `showSignature` and `showLogo`, and made `pageNumber` nullable. - In `CertSignController`: - Added an `@InitBinder` to convert empty multipart fields to `null`. - Extended `@PostMapping` to consume both `multipart/form-data` and `application/x-www-form-urlencoded`. - Wrapped `pageNumber` calculation in a null-check (`pageNumber = request.getPageNumber() != null ? request.getPageNumber() - 1 : null`). - Changed signature-visualization and logo checks to `Boolean.TRUE.equals(...)` to avoid unboxing NPE. - Cleaned up imports and schema annotations in the request model. - **Why the change was made** - Prevent a 500 Internal Server Error caused by calling `.intValue()` on a null `pageNumber` when `showSignature=false` (invisible signatures). - Ensure that omitting `pageNumber` doesn’t break clients using the “try it out” swagger UI or `curl`-based requests. - **Any challenges encountered** - Configuring Spring’s data binder to treat empty file inputs as `null` required a custom `PropertyEditorSupport`. - Balancing backward compatibility with stricter type handling (switching from primitive `boolean` to boxed `Boolean`). Closes #3459 --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] 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) - [x] I have performed a self-review of my own code - [x] 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. --- .../api/security/CertSignController.java | 39 ++++++++++++++----- .../api/security/SignPDFWithCertRequest.java | 12 +++--- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java index 7e1f2601f..58e5b848c 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java @@ -1,6 +1,7 @@ package stirling.software.SPDF.controller.api.security; import java.awt.*; +import java.beans.PropertyEditorSupport; import java.io.*; import java.nio.file.Files; import java.security.*; @@ -53,7 +54,10 @@ import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; import org.bouncycastle.pkcs.PKCSException; import org.springframework.core.io.ClassPathResource; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -82,6 +86,18 @@ public class CertSignController { Security.addProvider(new BouncyCastleProvider()); } + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor( + MultipartFile.class, + new PropertyEditorSupport() { + @Override + public void setAsText(String text) throws IllegalArgumentException { + setValue(null); + } + }); + } + private final CustomPDFDocumentFactory pdfDocumentFactory; private static void sign( @@ -103,8 +119,7 @@ public class CertSignController { signature.setLocation(location); signature.setReason(reason); signature.setSignDate(Calendar.getInstance()); - - if (showSignature) { + if (Boolean.TRUE.equals(showSignature)) { SignatureOptions signatureOptions = new SignatureOptions(); signatureOptions.setVisualSignature( instance.createVisibleSignature(doc, signature, pageNumber, showLogo)); @@ -121,13 +136,18 @@ public class CertSignController { } } - @PostMapping(consumes = "multipart/form-data", value = "/cert-sign") + @PostMapping( + consumes = { + MediaType.MULTIPART_FORM_DATA_VALUE, + MediaType.APPLICATION_FORM_URLENCODED_VALUE + }, + value = "/cert-sign") @Operation( summary = "Sign PDF with a Digital Certificate", description = "This endpoint accepts a PDF file, a digital certificate and related" - + " information to sign the PDF. It then returns the digitally signed PDF" - + " file. Input:PDF Output:PDF Type:SISO") + + " information to sign the PDF. It then returns the digitally signed PDF" + + " file. Input:PDF Output:PDF Type:SISO") public ResponseEntity signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request) throws Exception { MultipartFile pdf = request.getFileInput(); @@ -137,12 +157,13 @@ public class CertSignController { MultipartFile p12File = request.getP12File(); MultipartFile jksfile = request.getJksFile(); String password = request.getPassword(); - Boolean showSignature = request.isShowSignature(); + Boolean showSignature = request.getShowSignature(); String reason = request.getReason(); String location = request.getLocation(); String name = request.getName(); - Integer pageNumber = request.getPageNumber() - 1; - Boolean showLogo = request.isShowLogo(); + // Convert 1-indexed page number (user input) to 0-indexed page number (API requirement) + Integer pageNumber = request.getPageNumber() != null ? (request.getPageNumber() - 1) : null; + Boolean showLogo = request.getShowLogo(); if (certType == null) { throw new IllegalArgumentException("Cert type must be provided"); @@ -279,7 +300,7 @@ public class CertSignController { widget.setAppearance(appearance); try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream)) { - if (showLogo) { + if (Boolean.TRUE.equals(showLogo)) { cs.saveGraphicsState(); PDExtendedGraphicsState extState = new PDExtendedGraphicsState(); extState.setBlendMode(BlendMode.MULTIPLY); diff --git a/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java b/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java index b0266f307..d9fe92def 100644 --- a/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java +++ b/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java @@ -20,7 +20,8 @@ public class SignPDFWithCertRequest extends PDFFile { @Schema( description = - "The private key for the digital certificate (required for PEM type certificates)") + "The private key for the digital certificate (required for PEM type" + + " certificates)") private MultipartFile privateKeyFile; @Schema(description = "The digital certificate (required for PEM type certificates)") @@ -32,11 +33,11 @@ public class SignPDFWithCertRequest extends PDFFile { @Schema(description = "The JKS keystore file (Java Key Store)") private MultipartFile jksFile; - @Schema(description = "The password for the keystore or the private key") + @Schema(description = "The password for the keystore or the private key", format = "password") private String password; @Schema(description = "Whether to visually show the signature in the PDF file") - private boolean showSignature; + private Boolean showSignature; @Schema(description = "The reason for signing the PDF") private String reason; @@ -49,9 +50,10 @@ public class SignPDFWithCertRequest extends PDFFile { @Schema( description = - "The page number where the signature should be visible. This is required if showSignature is set to true") + "The page number where the signature should be visible. This is required if" + + " showSignature is set to true") private Integer pageNumber; @Schema(description = "Whether to visually show a signature logo along with the signature") - private boolean showLogo; + private Boolean showLogo; } From 5b0eaec4365ac2a9ba1cd300d96c2980c9cb51c6 Mon Sep 17 00:00:00 2001 From: Ludy Date: Wed, 7 May 2025 10:20:21 +0200 Subject: [PATCH 14/15] Add Email Sending Service with Attachment Support (#3455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes Please provide a summary of the changes, including: - **What was changed** - Introduced a new `EmailService` for asynchronous email delivery with attachment support. - Added `MailConfig` to configure a `JavaMailSender` bean using SMTP settings from `ApplicationProperties`. - Created `EmailController` endpoint (`/api/v1/general/send-email`) to accept multipart/form-data requests for sending emails. - Defined an `Email` API model to encapsulate recipient, subject, body, and file input. - Extended `ApplicationProperties` to include a nested `Mail` class for SMTP host, port, username/password, and sender address. - Updated `settings.yml.template` to include SMTP configuration placeholders. - Enhanced `.github/labeler-config.yml` to cover all new security- and API-related source files for automated labeling. - **Why the change was made** - To enable Stirling-PDF to notify users via email—particularly useful for sending generated PDFs or alerts—directly from the application. - To centralize mail server configuration in application properties and streamline onboarding for new environments. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] 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) - [x] I have performed a self-review of my own code - [x] 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. --- .github/labeler-config.yml | 18 +++- build.gradle | 19 ++--- .../config/security/mail/EmailService.java | 63 ++++++++++++++ .../SPDF/config/security/mail/MailConfig.java | 54 ++++++++++++ .../SPDF/controller/api/EmailController.java | 57 +++++++++++++ .../SPDF/model/ApplicationProperties.java | 12 +++ .../software/SPDF/model/api/Email.java | 39 +++++++++ src/main/resources/settings.yml.template | 8 ++ .../security/mail/EmailServiceTest.java | 64 ++++++++++++++ .../controller/api/EmailControllerTest.java | 84 +++++++++++++++++++ 10 files changed, 406 insertions(+), 12 deletions(-) create mode 100644 src/main/java/stirling/software/SPDF/config/security/mail/EmailService.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/mail/MailConfig.java create mode 100644 src/main/java/stirling/software/SPDF/controller/api/EmailController.java create mode 100644 src/main/java/stirling/software/SPDF/model/api/Email.java create mode 100644 src/test/java/stirling/software/SPDF/config/security/mail/EmailServiceTest.java create mode 100644 src/test/java/stirling/software/SPDF/controller/api/EmailControllerTest.java diff --git a/.github/labeler-config.yml b/.github/labeler-config.yml index a0a634840..bb52c7b85 100644 --- a/.github/labeler-config.yml +++ b/.github/labeler-config.yml @@ -27,18 +27,34 @@ Back End: Security: - changed-files: + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/interfaces/DatabaseInterface.java' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/DatabaseController.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/EmailController.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/H2SQLController.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/DatabaseWebController.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/UserController.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/api/Email.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/exception/BackupNotFoundException.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/exception/NoProviderFoundExceptionjava' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/provider/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AuthenticationType.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/BackupNotFoundException.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/ApiKeyAuthenticationToken.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AttemptCounter.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/Authority.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/PersistentLogin.java' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/SessionEntity.java' - any-glob-to-any-file: 'scripts/download-security-jar.sh' - any-glob-to-any-file: '.github/workflows/dependency-review.yml' - any-glob-to-any-file: '.github/workflows/scorecards.yml' API: - changed-files: + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/OpenApiConfig.java' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/MetricsController.java' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/**/*' + - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/api/**/*' - any-glob-to-any-file: 'scripts/png_to_webp.py' - any-glob-to-any-file: 'split_photos.py' - any-glob-to-any-file: '.github/workflows/swagger.yml' diff --git a/build.gradle b/build.gradle index 76277cc99..e91f0a467 100644 --- a/build.gradle +++ b/build.gradle @@ -51,16 +51,20 @@ sourceSets { main { java { if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") { + exclude "stirling/software/SPDF/config/interfaces/DatabaseInterface.java" exclude "stirling/software/SPDF/config/security/**" exclude "stirling/software/SPDF/controller/api/DatabaseController.java" - exclude "stirling/software/SPDF/controller/api/UserController.java" + exclude "stirling/software/SPDF/controller/api/EmailController.java" exclude "stirling/software/SPDF/controller/api/H2SQLCondition.java" + exclude "stirling/software/SPDF/controller/api/UserController.java" exclude "stirling/software/SPDF/controller/web/AccountWebController.java" exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java" + exclude "stirling/software/SPDF/model/api/Email.java" exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java" exclude "stirling/software/SPDF/model/AttemptCounter.java" exclude "stirling/software/SPDF/model/Authority.java" - exclude "stirling/software/SPDF/model/BackupNotFoundException.java" + exclude "stirling/software/SPDF/model/exception/BackupNotFoundException.java" + exclude "stirling/software/SPDF/model/exception/NoProviderFoundException.java" exclude "stirling/software/SPDF/model/PersistentLogin.java" exclude "stirling/software/SPDF/model/SessionEntity.java" exclude "stirling/software/SPDF/model/User.java" @@ -78,16 +82,8 @@ sourceSets { java { if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") { exclude "stirling/software/SPDF/config/security/**" - exclude "stirling/software/SPDF/controller/api/UserControllerTest.java" - exclude "stirling/software/SPDF/controller/api/DatabaseControllerTest.java" - exclude "stirling/software/SPDF/controller/web/AccountWebControllerTest.java" - exclude "stirling/software/SPDF/controller/web/DatabaseWebControllerTest.java" exclude "stirling/software/SPDF/model/ApiKeyAuthenticationTokenTest.java" - exclude "stirling/software/SPDF/model/AttemptCounterTest.java" - exclude "stirling/software/SPDF/model/AuthorityTest.java" - exclude "stirling/software/SPDF/model/PersistentLoginTest.java" - exclude "stirling/software/SPDF/model/SessionEntityTest.java" - exclude "stirling/software/SPDF/model/UserTest.java" + exclude "stirling/software/SPDF/controller/api/EmailControllerTest.java" exclude "stirling/software/SPDF/repository/**" } @@ -459,6 +455,7 @@ dependencies { implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE" implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion" + 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" diff --git a/src/main/java/stirling/software/SPDF/config/security/mail/EmailService.java b/src/main/java/stirling/software/SPDF/config/security/mail/EmailService.java new file mode 100644 index 000000000..8939fbab6 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/mail/EmailService.java @@ -0,0 +1,63 @@ +package stirling.software.SPDF.config.security.mail; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; + +import lombok.RequiredArgsConstructor; + +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.api.Email; + +/** + * Service class responsible for sending emails, including those with attachments. It uses + * JavaMailSender to send the email and is designed to handle both the message content and file + * attachments. + */ +@Service +@RequiredArgsConstructor +@ConditionalOnProperty(value = "mail.enabled", havingValue = "true", matchIfMissing = false) +public class EmailService { + + private final JavaMailSender mailSender; + private final ApplicationProperties applicationProperties; + + /** + * Sends an email with an attachment asynchronously. This method is annotated with @Async, which + * means it will be executed asynchronously. + * + * @param email The Email object containing the recipient, subject, body, and file attachment. + * @throws MessagingException If there is an issue with creating or sending the email. + */ + @Async + public void sendEmailWithAttachment(Email email) throws MessagingException { + ApplicationProperties.Mail mailProperties = applicationProperties.getMail(); + MultipartFile file = email.getFileInput(); + + // Creates a MimeMessage to represent the email + MimeMessage message = mailSender.createMimeMessage(); + + // Helper class to set up the message content and attachments + MimeMessageHelper helper = new MimeMessageHelper(message, true); + + // Sets the recipient, subject, body, and sender email + helper.addTo(email.getTo()); + helper.setSubject(email.getSubject()); + helper.setText( + email.getBody(), + true); // The "true" here indicates that the body contains HTML content. + helper.setFrom(mailProperties.getFrom()); + + // Adds the attachment to the email + helper.addAttachment(file.getOriginalFilename(), file); + + // Sends the email via the configured mail sender + mailSender.send(message); + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/mail/MailConfig.java b/src/main/java/stirling/software/SPDF/config/security/mail/MailConfig.java new file mode 100644 index 000000000..68c2fe35d --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/mail/MailConfig.java @@ -0,0 +1,54 @@ +package stirling.software.SPDF.config.security.mail; + +import java.util.Properties; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.model.ApplicationProperties; + +/** + * This configuration class provides the JavaMailSender bean, which is used to send emails. It reads + * email server settings from the configuration (ApplicationProperties) and configures the mail + * client (JavaMailSender). + */ +@Configuration +@Slf4j +@AllArgsConstructor +@ConditionalOnProperty(value = "mail.enabled", havingValue = "true", matchIfMissing = false) +public class MailConfig { + + private final ApplicationProperties applicationProperties; + + @Bean + public JavaMailSender javaMailSender() { + + ApplicationProperties.Mail mailProperties = applicationProperties.getMail(); + + // Creates a new instance of JavaMailSenderImpl, which is a Spring implementation + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(mailProperties.getHost()); + mailSender.setPort(mailProperties.getPort()); + mailSender.setUsername(mailProperties.getUsername()); + mailSender.setPassword(mailProperties.getPassword()); + mailSender.setDefaultEncoding("UTF-8"); + + // Retrieves the JavaMail properties to configure additional SMTP parameters + Properties props = mailSender.getJavaMailProperties(); + + // Enables SMTP authentication + props.put("mail.smtp.auth", "true"); + + // Enables STARTTLS to encrypt the connection if supported by the SMTP server + props.put("mail.smtp.starttls.enable", "true"); + + // Returns the configured mail sender, ready to send emails + return mailSender; + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/api/EmailController.java b/src/main/java/stirling/software/SPDF/controller/api/EmailController.java new file mode 100644 index 000000000..3b91368ef --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/EmailController.java @@ -0,0 +1,57 @@ +package stirling.software.SPDF.controller.api; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.tags.Tag; + +import jakarta.mail.MessagingException; +import jakarta.validation.Valid; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.config.security.mail.EmailService; +import stirling.software.SPDF.model.api.Email; + +/** + * Controller for handling email-related API requests. This controller exposes an endpoint for + * sending emails with attachments. + */ +@RestController +@RequestMapping("/api/v1/general") +@RequiredArgsConstructor +@Slf4j +@Tag(name = "General", description = "General APIs") +@ConditionalOnProperty(value = "mail.enabled", havingValue = "true", matchIfMissing = false) +public class EmailController { + private final EmailService emailService; + + /** + * Endpoint to send an email with an attachment. This method consumes a multipart/form-data + * request containing the email details and attachment. + * + * @param email The Email object containing recipient address, subject, body, and file + * attachment. + * @return ResponseEntity with success or error message. + */ + @PostMapping(consumes = "multipart/form-data", value = "/send-email") + public ResponseEntity sendEmailWithAttachment(@Valid @ModelAttribute Email email) { + try { + // Calls the service to send the email with attachment + emailService.sendEmailWithAttachment(email); + return ResponseEntity.ok("Email sent successfully"); + } catch (MessagingException e) { + // Catches any messaging exception (e.g., invalid email address, SMTP server issues) + String errorMsg = "Failed to send email: " + e.getMessage(); + log.error(errorMsg, e); // Logging the detailed error + // Returns an error response with status 500 (Internal Server Error) + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMsg); + } + } +} diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java index d42429619..82a17ff2c 100644 --- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java +++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java @@ -82,6 +82,8 @@ public class ApplicationProperties { private Metrics metrics = new Metrics(); private AutomaticallyGenerated automaticallyGenerated = new AutomaticallyGenerated(); + private Mail mail = new Mail(); + private Premium premium = new Premium(); private EnterpriseEdition enterpriseEdition = new EnterpriseEdition(); private AutoPipeline autoPipeline = new AutoPipeline(); @@ -420,6 +422,16 @@ public class ApplicationProperties { } } + @Data + public static class Mail { + private boolean enabled; + private String host; + private int port; + private String username; + @ToString.Exclude private String password; + private String from; + } + @Data public static class Premium { private boolean enabled; diff --git a/src/main/java/stirling/software/SPDF/model/api/Email.java b/src/main/java/stirling/software/SPDF/model/api/Email.java new file mode 100644 index 000000000..21b5152e5 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/model/api/Email.java @@ -0,0 +1,39 @@ +package stirling.software.SPDF.model.api; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +import io.swagger.v3.oas.annotations.media.Schema; + + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ConditionalOnProperty(value = "mail.enabled", havingValue = "true", matchIfMissing = false) +public class Email extends GeneralFile { + + @Schema( + description = "The recipient's email address", + requiredMode = Schema.RequiredMode.REQUIRED, + format = "email") + private String to; + + @Schema( + description = "The subject of the email", + defaultValue = "Stirling Software PDF Notification", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String subject; + + @Schema( + description = "The body of the email", + requiredMode = Schema.RequiredMode.NOT_REQUIRED, + defaultValue = + "This message was automatically generated by Stirling-PDF, an innovative" + + " solution from Stirling Software. For more information, visit our website.

Please do" + + " not reply directly to this email.") + private String body; +} diff --git a/src/main/resources/settings.yml.template b/src/main/resources/settings.yml.template index 1c3ee32ae..201f875dd 100644 --- a/src/main/resources/settings.yml.template +++ b/src/main/resources/settings.yml.template @@ -76,6 +76,14 @@ premium: apiKey: '' appId: '' +mail: + enabled: true # set to 'true' to enable sending emails + host: smtp.example.com # SMTP server hostname + port: 587 # SMTP server port + username: '' # SMTP server username + password: '' # SMTP server password + from: '' # sender email address + legal: termsAndConditions: https://www.stirlingpdf.com/terms-and-conditions # URL to the terms and conditions of your application (e.g. https://example.com/terms). Empty string to disable or filename to load from local file in static folder privacyPolicy: https://www.stirlingpdf.com/privacy-policy # URL to the privacy policy of your application (e.g. https://example.com/privacy). Empty string to disable or filename to load from local file in static folder diff --git a/src/test/java/stirling/software/SPDF/config/security/mail/EmailServiceTest.java b/src/test/java/stirling/software/SPDF/config/security/mail/EmailServiceTest.java new file mode 100644 index 000000000..63c38e9c3 --- /dev/null +++ b/src/test/java/stirling/software/SPDF/config/security/mail/EmailServiceTest.java @@ -0,0 +1,64 @@ +package stirling.software.SPDF.config.security.mail; + +import static org.mockito.Mockito.*; + +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.web.multipart.MultipartFile; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.api.Email; + +@ExtendWith(MockitoExtension.class) +public class EmailServiceTest { + + @Mock + private JavaMailSender mailSender; + + @Mock + private ApplicationProperties applicationProperties; + + @Mock + private ApplicationProperties.Mail mailProperties; + + @Mock + private MultipartFile fileInput; + + @InjectMocks + private EmailService emailService; + + @Test + void testSendEmailWithAttachment() throws MessagingException { + // Mock the values returned by ApplicationProperties + when(applicationProperties.getMail()).thenReturn(mailProperties); + when(mailProperties.getFrom()).thenReturn("no-reply@stirling-software.com"); + + // Create a mock Email object + Email email = new Email(); + email.setTo("test@example.com"); + email.setSubject("Test Email"); + email.setBody("This is a test email."); + email.setFileInput(fileInput); + + // Mock MultipartFile behavior + when(fileInput.getOriginalFilename()).thenReturn("testFile.txt"); + + // Mock MimeMessage + MimeMessage mimeMessage = mock(MimeMessage.class); + + // Configure mailSender to return the mocked MimeMessage + when(mailSender.createMimeMessage()).thenReturn(mimeMessage); + + // Call the service method + emailService.sendEmailWithAttachment(email); + + // Verify that the email was sent using mailSender + verify(mailSender).send(mimeMessage); + } +} diff --git a/src/test/java/stirling/software/SPDF/controller/api/EmailControllerTest.java b/src/test/java/stirling/software/SPDF/controller/api/EmailControllerTest.java new file mode 100644 index 000000000..25aa89479 --- /dev/null +++ b/src/test/java/stirling/software/SPDF/controller/api/EmailControllerTest.java @@ -0,0 +1,84 @@ +package stirling.software.SPDF.controller.api; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import jakarta.mail.MessagingException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.multipart.MultipartFile; +import stirling.software.SPDF.config.security.mail.EmailService; +import stirling.software.SPDF.model.api.Email; + +@ExtendWith(MockitoExtension.class) +public class EmailControllerTest { + + private MockMvc mockMvc; + + @Mock private EmailService emailService; + + @InjectMocks private EmailController emailController; + + @Mock private MultipartFile fileInput; + + @BeforeEach + void setUp() { + // Set up the MockMvc instance for testing + mockMvc = MockMvcBuilders.standaloneSetup(emailController).build(); + } + + @Test + void testSendEmailWithAttachmentSuccess() throws Exception { + // Create a mock Email object + Email email = new Email(); + email.setTo("test@example.com"); + email.setSubject("Test Email"); + email.setBody("This is a test email."); + email.setFileInput(fileInput); + + // Mock the service to not throw any exception + doNothing().when(emailService).sendEmailWithAttachment(any(Email.class)); + + // Perform the request and verify the response + mockMvc.perform( + multipart("/api/v1/general/send-email") + .file("fileInput", "dummy-content".getBytes()) + .param("to", email.getTo()) + .param("subject", email.getSubject()) + .param("body", email.getBody())) + .andExpect(status().isOk()) + .andExpect(content().string("Email sent successfully")); + } + + @Test + void testSendEmailWithAttachmentFailure() throws Exception { + // Create a mock Email object + Email email = new Email(); + email.setTo("test@example.com"); + email.setSubject("Test Email"); + email.setBody("This is a test email."); + email.setFileInput(fileInput); + + // Mock the service to throw a MessagingException + doThrow(new MessagingException("Failed to send email")) + .when(emailService) + .sendEmailWithAttachment(any(Email.class)); + + // Perform the request and verify the response + mockMvc.perform( + multipart("/api/v1/general/send-email") + .file("fileInput", "dummy-content".getBytes()) + .param("to", email.getTo()) + .param("subject", email.getSubject()) + .param("body", email.getBody())) + .andExpect(status().isInternalServerError()) + .andExpect(content().string("Failed to send email: Failed to send email")); + } +} From 512e9d72369d4195e04b4eb8d5f7e2299f0a0500 Mon Sep 17 00:00:00 2001 From: "stirlingbot[bot]" <195170888+stirlingbot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 13:29:51 +0100 Subject: [PATCH 15/15] Update 3rd Party Licenses (#3487) 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> --- .../resources/static/3rdPartyLicenses.json | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/resources/static/3rdPartyLicenses.json b/src/main/resources/static/3rdPartyLicenses.json index 4395d1fa0..da8718489 100644 --- a/src/main/resources/static/3rdPartyLicenses.json +++ b/src/main/resources/static/3rdPartyLicenses.json @@ -1011,6 +1011,13 @@ "moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception", "moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html" }, + { + "moduleName": "org.eclipse.angus:jakarta.mail", + "moduleUrl": "https://www.eclipse.org", + "moduleVersion": "2.0.3", + "moduleLicense": "GPL2 w/ CPE", + "moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html" + }, { "moduleName": "org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jakarta-client", "moduleUrl": "https://jetty.org/", @@ -1529,6 +1536,13 @@ "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, + { + "moduleName": "org.springframework.boot:spring-boot-starter-mail", + "moduleUrl": "https://spring.io/projects/spring-boot", + "moduleVersion": "3.4.5", + "moduleLicense": "Apache License, Version 2.0", + "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" + }, { "moduleName": "org.springframework.boot:spring-boot-starter-oauth2-client", "moduleUrl": "https://spring.io/projects/spring-boot", @@ -1669,6 +1683,13 @@ "moduleLicense": "Apache License, Version 2.0", "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" }, + { + "moduleName": "org.springframework:spring-context-support", + "moduleUrl": "https://github.com/spring-projects/spring-framework", + "moduleVersion": "6.2.6", + "moduleLicense": "Apache License, Version 2.0", + "moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0" + }, { "moduleName": "org.springframework:spring-core", "moduleUrl": "https://github.com/spring-projects/spring-framework",