Compare commits

..

25 Commits

Author SHA1 Message Date
stirlingbot[bot]
6ed1e046d3
Update 3rd Party Licenses
Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
2025-05-27 12:03:13 +00:00
Dario Ghunney Ware
bedc3d02d7
New common module (#3573)
# Description of Changes

Introduced a new `common` module for shared libs and commonly used
classes. See the screenshot below for the file structure and classes
that have been moved.

---
<img width="452" alt="Screenshot 2025-05-22 at 11 46 56"
src="https://github.com/user-attachments/assets/c9badabc-48f9-4079-b83e-7cfde0fb840f"
/>
<img width="470" alt="Screenshot 2025-05-22 at 11 47 30"
src="https://github.com/user-attachments/assets/e8315b09-2e78-4c50-b9de-4dd9b9b0ecb1"
/>

## 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)
- [x] 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.
2025-05-27 13:01:52 +01:00
Ludy
be1a9cc8da
Standardize GitHub App Bot Authentication Across Workflows (#3582)
# Description of Changes

Please provide a summary of the changes, including:

- **What was changed**  
- Removed individual `actions/create-github-app-token` steps and
replaced them with a centralized `setup-bot` custom action across all
workflows.
- Updated steps to use `steps.setup-bot.outputs` instead of
`steps.generate-token.outputs`.
- Standardized step names and ordering (e.g. checkout before bot setup).
- Simplified `sync_files.yml` by eliminating the `read_bot_entries` job
and directly using `setup-bot` outputs.
- Added or adjusted permissions where required (e.g.
`repository-projects: write` in `licenses-update.yml`).

- **Why the change was made**  
- To centralize and standardize GitHub App authentication logic, reduce
duplication, and improve maintainability of CI workflows.
- To ensure a consistent bot identity (app slug, token,
committer/author) across all actions and PR automation.
- To streamline workflow configurations and make future updates easier.

---

## 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.
2025-05-27 12:36:41 +01:00
stirlingbot[bot]
055c642136
Update 3rd Party Licenses (#3598)
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>
2025-05-27 12:22:09 +01:00
stirlingbot[bot]
61521b5bf3
🌐 Sync Translations + Update README Progress Table (#3568)
### Description of Changes

This Pull Request was automatically generated to synchronize updates to
translation files and documentation. Below are the details of the
changes made:

#### **1. Synchronization of Translation Files**
- Updated translation files (`messages_*.properties`) to reflect changes
in the reference file `messages_en_GB.properties`.
- Ensured consistency and synchronization across all supported language
files.
- Highlighted any missing or incomplete translations.

#### **2. Update README.md**
- Generated the translation progress table in `README.md`.
- Added a summary of the current translation status for all supported
languages.
- Included up-to-date statistics on translation coverage.

#### **Why these changes are necessary**
- Keeps translation files aligned with the latest reference updates.
- Ensures the documentation reflects the current translation progress.

---

Auto-generated by [create-pull-request][1].

[1]: https://github.com/peter-evans/create-pull-request

Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-05-27 12:21:03 +01:00
DongHe
ccf1b23d67
update messages_zh_CN.properties (#3597)
# Description of Changes

Please provide a summary of the changes, including:

- What was changed
Added and optimized the Chinese (Simplified) translation
- Why the change was made
The original project lacks a complete simplified Chinese translation and
thus cannot cover the content related to the survey and Cookie Settings.
- Any challenges encountered

Closes #(issue_number)

---

## 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)
- [x] 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)
- [x] 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: justeHe <justeHe@noreply.github.com>
2025-05-27 12:19:04 +01:00
Ludy
14f76b6146
Bump Pre-commit Hooks and Java Formatter to Latest Versions (#3589)
# Description of Changes

Please provide a summary of the changes, including:

- **What was changed**:  
- Updated `ruff` from v0.11.6 to v0.11.11 and `gitleaks` from v8.24.3 to
v8.26.0 in `.pre-commit-config.yaml`
- Bumped Java formatter version from 1.26.0 to 1.27.0 in VSCode settings
(`.vscode/settings.json`) and in `build.gradle` (googleJavaFormat)
  - Standardized quoting for the `jacoco` plugin in `build.gradle`  
- Cleaned up indentation and removed extra whitespace in test
dependencies

- **Why the change was made**:  
To keep our linting and formatting tools up to date with the latest
stable releases—bringing in bug fixes, performance improvements, and
maintaining consistency across 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.

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2025-05-27 12:17:25 +01:00
stirlingbot[bot]
6780bb4a30
🤖 format everything with pre-commit by <stirlingbot> (#3588)
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>
2025-05-27 12:16:07 +01:00
dependabot[bot]
feb84f001c
Bump org.springframework.session:spring-session-core from 3.4.3 to 3.5.0 (#3591)
[//]: # (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.session:spring-session-core](https://github.com/spring-projects/spring-session)
from 3.4.3 to 3.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-session/releases">org.springframework.session:spring-session-core's
releases</a>.</em></p>
<blockquote>
<h2>3.5.0</h2>
<h2>🪲 Bug Fixes</h2>
<ul>
<li>Fix Race Condition in Integration Tests Using Redis
SessionEventRegistry <a
href="https://redirect.github.com/spring-projects/spring-session/issues/3400">#3400</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Bump com.fasterxml.jackson.core:jackson-databind from 2.18.3 to
2.18.4 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3393">#3393</a></li>
<li>Bump io.projectreactor:reactor-bom from 2024.0.5 to 2024.0.6 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3395">#3395</a></li>
<li>Bump io.projectreactor:reactor-core from 3.6.16 to 3.6.17 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3394">#3394</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to
1.0.6 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3392">#3392</a></li>
<li>Bump io.spring.javaformat:spring-javaformat-checkstyle from 0.0.43
to 0.0.45 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3402">#3402</a></li>
<li>Bump io.spring.javaformat:spring-javaformat-gradle-plugin from
0.0.43 to 0.0.45 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3404">#3404</a></li>
<li>Bump org.springframework.data:spring-data-bom from 2025.0.0-RC1 to
2025.0.1-SNAPSHOT <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3397">#3397</a></li>
<li>Bump org.springframework.security:spring-security-bom from 6.5.0-RC1
to 6.5.1-SNAPSHOT <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3401">#3401</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.6 to 6.2.7 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3403">#3403</a></li>
<li>Spring Security 6.5.0 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3406">#3406</a></li>
<li>Update to Spring Data 2025.0.0 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3405">#3405</a></li>
</ul>
<h2>❤️ Contributors</h2>
<p>Thank you to all the contributors who worked on this release:</p>
<p><a href="https://github.com/rwinch"><code>@​rwinch</code></a></p>
<h2>3.5.0-RC1</h2>
<h2> New Features</h2>
<ul>
<li>Introduce CompositeHttpSessionIdResolver <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3264">#3264</a></li>
<li>Start JDBC transactions only when there is an update <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3330">#3330</a></li>
</ul>
<h2>🪲 Bug Fixes</h2>
<ul>
<li>Explicitly use junit-platform-launcher <a
href="https://redirect.github.com/spring-projects/spring-session/issues/3367">#3367</a></li>
<li>Fix jdbc session with special characters <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3316">#3316</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Bump io.projectreactor:reactor-bom from 2024.0.4 to 2024.0.5 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3380">#3380</a></li>
<li>Bump io.projectreactor:reactor-core from 3.6.15 to 3.6.16 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3381">#3381</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.3 to
1.0.4 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3377">#3377</a></li>
<li>Bump io.spring.gradle:spring-security-release-plugin from 1.0.4 to
1.0.5 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3387">#3387</a></li>
<li>Bump org.aspectj:aspectjweaver from 1.9.23 to 1.9.24 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3378">#3378</a></li>
<li>Bump org.hsqldb:hsqldb from 2.7.3 to 2.7.4 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3369">#3369</a></li>
<li>Bump org.mariadb.jdbc:mariadb-java-client from 3.5.2 to 3.5.3 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3371">#3371</a></li>
<li>Bump org.springframework.boot:spring-boot-gradle-plugin from
3.5.0-M3 to 3.5.0-SNAPSHOT <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3373">#3373</a></li>
<li>Bump org.springframework.data:spring-data-bom from 2025.0.0-M2 to
2025.0.0-SNAPSHOT <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3372">#3372</a></li>
<li>Bump org.springframework:spring-framework-bom from 6.2.5 to 6.2.6 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3384">#3384</a></li>
<li>Update to Spring Boot 3.5.0 (dependencies) <a
href="https://redirect.github.com/spring-projects/spring-session/issues/3368">#3368</a></li>
<li>Update to Spring Security 6.5.0-rc1 <a
href="https://redirect.github.com/spring-projects/spring-session/pull/3386">#3386</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="817b17251a"><code>817b172</code></a>
Release 3.5.0</li>
<li><a
href="5a9c22000a"><code>5a9c220</code></a>
Update to Spring Security 6.5.0</li>
<li><a
href="ce5efb7e51"><code>ce5efb7</code></a>
Update to Spring Data 2025.0.0</li>
<li><a
href="d6391a8a42"><code>d6391a8</code></a>
Revert &quot;Bump
io.spring.javaformat:spring-javaformat-checkstyle&quot;</li>
<li><a
href="f75cd2454a"><code>f75cd24</code></a>
Revert &quot;Bump
org.springframework.security:spring-security-bom&quot;</li>
<li><a
href="ca46943101"><code>ca46943</code></a>
Bump org.springframework.security:spring-security-bom</li>
<li><a
href="bf09912a7f"><code>bf09912</code></a>
Bump io.spring.javaformat:spring-javaformat-checkstyle</li>
<li><a
href="ae2f60668b"><code>ae2f606</code></a>
Bump io.spring.javaformat:spring-javaformat-gradle-plugin</li>
<li><a
href="05e9a3ec75"><code>05e9a3e</code></a>
Bump org.springframework:spring-framework-bom from 6.2.6 to 6.2.7</li>
<li><a
href="6fb972d633"><code>6fb972d</code></a>
Bump io.spring.gradle:spring-security-release-plugin from 1.0.5 to
1.0.6</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-session/compare/3.4.3...3.5.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework.session:spring-session-core&package-manager=gradle&previous-version=3.4.3&new-version=3.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 12:14:42 +01:00
dependabot[bot]
8c061ea644
Bump springBootVersion from 3.4.5 to 3.5.0 (#3592)
[//]: # (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 `springBootVersion` from 3.4.5 to 3.5.0.
Updates `org.springframework.boot:spring-boot-starter-web` from 3.4.5 to
3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-web's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-jetty` from 3.4.5
to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-jetty's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-thymeleaf` from
3.4.5 to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-thymeleaf's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-security` from
3.4.5 to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-security's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-data-jpa` from
3.4.5 to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-data-jpa's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-oauth2-client`
from 3.4.5 to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-oauth2-client's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-mail` from 3.4.5
to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-mail's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `org.springframework.boot:spring-boot-starter-test` from 3.4.5
to 3.5.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot:spring-boot-starter-test's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a...

_Description has been truncated_

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 12:14:30 +01:00
dependabot[bot]
ea5515b614
Bump org.mockito:mockito-core from 5.17.0 to 5.18.0 (#3593)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito)
from 5.17.0 to 5.18.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/mockito/mockito/releases">org.mockito:mockito-core's
releases</a>.</em></p>
<blockquote>
<h2>v5.18.0</h2>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --><em>Changelog
generated by <a
href="https://github.com/shipkit/shipkit-changelog">Shipkit Changelog
Gradle Plugin</a></em><!-- raw HTML omitted --><!-- raw HTML omitted
--></p>
<h4>5.18.0</h4>
<ul>
<li>2025-05-20 - <a
href="https://github.com/mockito/mockito/compare/v5.17.0...v5.18.0">5
commit(s)</a> by Eugene Platonov, Patrick Doyle, Tim van der Lippe,
dependabot[bot]</li>
<li>Make vararg checks Scala friendly (for mockito-scala) [(<a
href="https://redirect.github.com/mockito/mockito/issues/3651">#3651</a>)](<a
href="https://redirect.github.com/mockito/mockito/pull/3651">mockito/mockito#3651</a>)</li>
<li>For UnfinishedStubbingException, suggest the possibility of another
thread [(<a
href="https://redirect.github.com/mockito/mockito/issues/3636">#3636</a>)](<a
href="https://redirect.github.com/mockito/mockito/pull/3636">mockito/mockito#3636</a>)</li>
<li>UnfinishedStubbingException ought to suggest the possibility of
another thread [(<a
href="https://redirect.github.com/mockito/mockito/issues/3635">#3635</a>)](<a
href="https://redirect.github.com/mockito/mockito/issues/3635">mockito/mockito#3635</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="06737471ea"><code>0673747</code></a>
Force Jacoco version for Android</li>
<li><a
href="65388f01eb"><code>65388f0</code></a>
Update Jacoco version to 0.8.13</li>
<li><a
href="60179ca10d"><code>60179ca</code></a>
Bump bytebuddy from 1.15.11 to 1.16.1</li>
<li><a
href="8f15169774"><code>8f15169</code></a>
Make vararg checks Scala friendly (<a
href="https://redirect.github.com/mockito/mockito/issues/3651">#3651</a>)</li>
<li><a
href="3a631cb870"><code>3a631cb</code></a>
Add hint for multithreading in <code>UnfinishedStubbingException</code>
(<a
href="https://redirect.github.com/mockito/mockito/issues/3636">#3636</a>)</li>
<li>See full diff in <a
href="https://github.com/mockito/mockito/compare/v5.17.0...v5.18.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.mockito:mockito-core&package-manager=gradle&previous-version=5.17.0&new-version=5.18.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 12:14:17 +01:00
dependabot[bot]
b1a6e1b481
Bump org.springframework.boot from 3.4.5 to 3.5.0 (#3594)
Bumps
[org.springframework.boot](https://github.com/spring-projects/spring-boot)
from 3.4.5 to 3.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/spring-projects/spring-boot/releases">org.springframework.boot's
releases</a>.</em></p>
<blockquote>
<h2>v3.5.0</h2>
<p>Full <a
href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes">release
notes for Spring Boot 3.5</a> are available on the wiki.</p>
<h2> New Features</h2>
<ul>
<li>Make heapdump endpoint restricted by default <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45624">#45624</a></li>
<li>Remove SSL status tag from metrics <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45602">#45602</a></li>
<li>Remove 'spring.http.client' deprecation and change
'spring.http.reactiveclient.settings' to 'spring.http.reactiveclient' <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45507">#45507</a></li>
</ul>
<h2>🐞 Bug Fixes</h2>
<ul>
<li>Unable to override/set nested ConfigurationProperties by passing as
a system property <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45639">#45639</a></li>
<li>ValidationAutoConfiguration triggers early initialization of
properties binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45618">#45618</a></li>
<li>Micrometer &quot;enable&quot; annotations property does not cover
observed aspect <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45617">#45617</a></li>
<li>spring.graphql.sse.timeout is no longer exposed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45613">#45613</a></li>
<li>SpringApplication.setEnvironmentPrefix is ignored when reading
SPRING_PROFILES_ACTIVE <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45549">#45549</a></li>
<li>IllegalStateException when extracting using layers a module with no
code of its own <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45449">#45449</a></li>
<li>Removed spring.batch.initialize-schema property is still considered
<a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45380">#45380</a></li>
<li>ReactorHttpClientBuilder does not offer a factory method to create
the HttpClient <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45378">#45378</a></li>
<li>Suggested values for spring.jpa.hibernate.ddl-auto are not aligned
with Hibernate <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45351">#45351</a></li>
<li>Custom default units declared on a field are ignored when binding
properties in a native image <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45347">#45347</a></li>
<li>DockerRegistryConfigAuthentication uses the wrong serverUrl as a
fallback for the Credentials helper <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45345">#45345</a></li>
<li>Various spring.datasource properties are mistakenly marked as
ignored <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45342">#45342</a></li>
<li>JerseyWebApplicationInitializer always gets loaded, setting a
ServletContext initParameter <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45297">#45297</a></li>
<li>DockerRegistryConfigAuthentication does not align with Docker CLI <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45292">#45292</a></li>
<li>Unlike the Docker CLI, &quot;\x00&quot; characters are not trimmed
from a decoded Docker Registry password <a
href="https://redirect.github.com/spring-projects/spring-boot/pull/45290">#45290</a></li>
<li>CloudFoundry security matcher logs a warning due to use of the
'ignoring()' method <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/32622">#32622</a></li>
</ul>
<h2>📔 Documentation</h2>
<ul>
<li>Document the java info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45634">#45634</a></li>
<li>Document the process info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45632">#45632</a></li>
<li>Document the os info contribution <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45630">#45630</a></li>
<li>Document typical spring.application.group and name use <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45628">#45628</a></li>
<li>Document that bean methods should be static when annotated with
<code>@ConfigurationPropertiesBinding</code> <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45626">#45626</a></li>
<li>Document the way that primary Kotlin constructors are used when
binding <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45553">#45553</a></li>
<li>Improve &quot;profile&quot; reference documentation with additional
admonitions <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45551">#45551</a></li>
<li>Improve setEnvironmentPrefix(...) reference documentation <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45376">#45376</a></li>
<li>Document all the available Testcontainers integrations <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45367">#45367</a></li>
<li>Document when a spring.config.import value is relative and when it
is fixed <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45363">#45363</a></li>
<li>Update org.cyclonedx.bom version in docs to 2.3.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45320">#45320</a></li>
<li>Update link to &quot;Parameter Name Retention&quot; section of
Spring Framework's release notes <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45299">#45299</a></li>
</ul>
<h2>🔨 Dependency Upgrades</h2>
<ul>
<li>Prevent upgrade to Prometheus Client 1.3.7 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45541">#45541</a></li>
<li>Upgrade to Couchbase Client 3.8.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45539">#45539</a></li>
<li>Upgrade to Elasticsearch 8.18.1 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45447">#45447</a></li>
<li>Upgrade to GraphQL Java 24.0 <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45588">#45588</a></li>
<li>Upgrade to Hibernate 6.6.15.Final <a
href="https://redirect.github.com/spring-projects/spring-boot/issues/45540">#45540</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8c2d645324"><code>8c2d645</code></a>
Release v3.5.0</li>
<li><a
href="0b49e78c21"><code>0b49e78</code></a>
Merge branch '3.4.x'</li>
<li><a
href="c684fa4050"><code>c684fa4</code></a>
Switch <code>make-default</code> for publish-to-sdkman to 3.5.x</li>
<li><a
href="5695192850"><code>5695192</code></a>
Ensure descendants are always recalculated on cache refresh</li>
<li><a
href="31f549efc6"><code>31f549e</code></a>
Merge branch '3.4.x'</li>
<li><a
href="68df6f5941"><code>68df6f5</code></a>
Next development version (v3.4.7-SNAPSHOT)</li>
<li><a
href="9f46877c7e"><code>9f46877</code></a>
Merge branch '3.4.x'</li>
<li><a
href="404a0df5e8"><code>404a0df</code></a>
Merge branch '3.3.x' into 3.4.x</li>
<li><a
href="e331846302"><code>e331846</code></a>
Next development version (v3.3.13-SNAPSHOT)</li>
<li><a
href="b142798bdb"><code>b142798</code></a>
Merge branch '3.4.x'</li>
<li>Additional commits viewable in <a
href="https://github.com/spring-projects/spring-boot/compare/v3.4.5...v3.5.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.springframework.boot&package-manager=gradle&previous-version=3.4.5&new-version=3.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 12:14:12 +01:00
Ludy
f2f11496a2
Fix Chinese localization split page numbering (#3574)
# Description of Changes

Please provide a summary of the changes, including:

- **What was changed**  
Updated the values of `split.desc.6`, `split.desc.7`, and `split.desc.8`
in `src/main/resources/messages_zh_CN.properties` to correct the page
numbers:

- **Why the change was made**  
The previous numbering was inconsistent and would have led to incorrect
split outputs in the Chinese UI. This ensures that users splitting a
document see the correct page ranges.

- **Translation Method**  
The correction of these translation strings was generated and verified
using AI assistance.

Closes #3529

---

## 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)

- [ ] 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.
2025-05-23 22:22:05 +01:00
Ludy
75c325d15a
Update messages_de_DE.properties (#3575)
# Description of Changes

Please provide a summary of the changes, including:

---

## 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>
2025-05-23 10:50:54 +01:00
daenur
adcfe629f2
Russian translation (#3572)
Update messages_ru_RU.properties

# 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

- [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)
- [ ] 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.
2025-05-22 10:44:14 +01:00
Ludy
35304a1491
Enhance email error handling and expand test coverage (#3561)
# Description of Changes

Please provide a summary of the changes, including:

- **What was changed**  
- **EmailController**: Added a `catch (MailSendException)` block to
handle invalid-address errors, log the exception, and return a 500
response with the raw error message.
- **EmailServiceTest**: Added unit tests for attachment-related error
cases (missing filename, null filename, missing file, null file) and
invalid “to” address (null or empty), expecting `MessagingException` or
`MailSendException`.
- **MailConfigTest**: New test class verifying `MailConfig.java`
correctly initializes `JavaMailSenderImpl` with host, port, username,
password, default encoding, and SMTP properties.
- **EmailControllerTest**: Refactored into a parameterized test
(`shouldHandleEmailRequests`) covering four scenarios: success, generic
messaging error, missing `to` parameter, and invalid address formatting.

- **Why the change was made**  
- To ensure invalid email addresses and missing attachments are handled
gracefully at the controller layer, providing clearer feedback to API
clients.
- To improve overall test coverage and guard against regressions in
email functionality.
  - To enforce correct mail configuration via automated tests.

---

## 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.
2025-05-21 15:42:08 +01:00
daenur
cc938e1751
Ukrainian translation (#3567)
Update messages_uk_UA.properties

# 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

- [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)
- [ ] 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.
2025-05-21 15:41:51 +01:00
Ludy
b65624cf57
Enforce Locale.US for Consistent Decimal Formatting in Byte-Size Output (#3562)
# Description of Changes

Please provide a summary of the changes, including:

- **What was changed**  
  - Added `import java.util.Locale;`  
- Updated the `String.format` call in `humanReadableByteCount` to use
`Locale.US`

- **Why the change was made**  
By default, `String.format` uses the JVM’s default locale, which in some
environments (e.g., Germany) formats decimals with a comma. Tests
expected a dot (`.`) as the decimal separator (e.g., `"1.0 KB"`), so we
force `Locale.US` to ensure consistent output across all locales.


---

## 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.
2025-05-21 15:41:11 +01:00
Anthony Stirling
8bfdb2abb5
Update home.html (#3560)
# 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.
2025-05-20 17:42:42 +01:00
Reece Browne
70349fb7e3
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.
2025-05-20 12:08:20 +01:00
stirlingbot[bot]
bef86b44e4
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>
2025-05-20 12:07:03 +01:00
Anthony Stirling
46cc2e05df
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`
2025-05-20 12:05:18 +01:00
Anthony Stirling
c8e25f4c5a
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>
2025-05-20 12:02:26 +01:00
Anthony Stirling
218d21f07a
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`
2025-05-20 12:02:10 +01:00
Anthony Stirling
9fe49c494d
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)*
2025-05-20 12:02:01 +01:00
273 changed files with 2899 additions and 2710 deletions

33
.github/actions/setup-bot/action.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: 'Setup GitHub App Bot'
description: 'Generates a GitHub App Token and configures Git for a bot'
inputs:
app-id:
description: 'GitHub App ID'
required: True
private-key:
description: 'GitHub App Private Key'
required: True
outputs:
token:
description: 'Generated GitHub App Token'
value: ${{ steps.generate-token.outputs.token }}
committer:
description: 'Committer string for Git'
value: "${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>"
app-slug:
description: 'GitHub App slug'
value: ${{ steps.generate-token.outputs.app-slug }}
runs:
using: 'composite'
steps:
- name: Generate a GitHub App Token
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
with:
app-id: ${{ inputs.app-id }}
private-key: ${{ inputs.private-key }}
- name: Configure Git
run: |
git config --global user.name "${{ steps.generate-token.outputs.app-slug }}[bot]"
git config --global user.email "${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com"
shell: bash

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
issues: write # Allow posting comments on issues/PRs
pull-requests: write
pull-requests: write # Allow writing to pull requests
steps:
- name: Harden Runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
@ -25,10 +25,12 @@ jobs:
- name: Checkout main branch first
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- name: Setup GitHub App Bot
id: setup-bot
uses: ./.github/actions/setup-bot
with:
python-version: "3.12"
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Get PR data
id: get-pr-data
@ -219,7 +221,7 @@ jobs:
const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary"));
// Only update or create comments by the action user
const expectedActor = "github-actions[bot]";
const expectedActor = "${{ steps.setup-bot.outputs.app-slug }}[bot]";
if (comment && comment.user.login === expectedActor) {
// Update existing comment

View File

@ -16,52 +16,50 @@ jobs:
permissions:
contents: write
pull-requests: write
repository-projects: write # Required for enabling automerge
steps:
- name: Harden Runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Setup GitHub App Bot
id: setup-bot
uses: ./.github/actions/setup-bot
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
java-version: "17"
distribution: "adopt"
- uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0
- name: Setup Gradle
uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0
- name: check the licenses for compatibility
- name: Check licenses for compatibility
run: ./gradlew clean checkLicense
- name: FAILED - check the licenses for compatibility
- name: Upload artifact on failure
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dependencies-without-allowed-license.json
path: |
build/reports/dependency-license/dependencies-without-allowed-license.json
path: build/reports/dependency-license/dependencies-without-allowed-license.json
retention-days: 3
- name: Move and Rename License File
- name: Move and rename license file
run: |
mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json
- name: Set up git config
run: |
git config --global user.name "stirlingbot[bot]"
git config --global user.email "1113334+stirlingbot[bot]@users.noreply.github.com"
- name: Run git add
- name: Commit changes
run: |
git add src/main/resources/static/3rdPartyLicenses.json
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
@ -71,15 +69,15 @@ jobs:
if: env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ steps.generate-token.outputs.token }}
token: ${{ steps.setup-bot.outputs.token }}
commit-message: "Update 3rd Party Licenses"
committer: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>"
author: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>"
committer: ${{ steps.setup-bot.outputs.committer }}
author: ${{ steps.setup-bot.outputs.committer }}
signoff: true
branch: update-3rd-party-licenses
title: "Update 3rd Party Licenses"
body: |
Auto-generated by StirlingBot
Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot]
labels: licenses,github-actions
draft: false
delete-branch: true
@ -89,4 +87,4 @@ jobs:
if: steps.cpr.outputs.pull-request-operation == 'created'
run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
GH_TOKEN: ${{ steps.setup-bot.outputs.token }}

View File

@ -20,58 +20,49 @@ jobs:
with:
egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Get GitHub App User ID
id: get-user-id
run: echo "user-id=$(gh api "/users/${{ steps.generate-token.outputs.app-slug }}[bot]" --jq .id)" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
- id: committer
run: |
echo "string=${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>" >> "$GITHUB_OUTPUT"
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Setup GitHub App Bot
id: setup-bot
uses: ./.github/actions/setup-bot
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: 3.12
cache: 'pip' # caching pip dependencies
- name: Run Pre-Commit Hooks
run: |
pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt
- run: pre-commit run --all-files -c .pre-commit-config.yaml
continue-on-error: true
- name: Set up git config
run: |
git config --global user.name ${{ steps.generate-token.outputs.app-slug }}[bot]
git config --global user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com"
- name: git add
run: |
git add .
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
- name: Create Pull Request
if: env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ steps.generate-token.outputs.token }}
token: ${{ steps.setup-bot.outputs.token }}
commit-message: ":file_folder: pre-commit"
committer: ${{ steps.committer.outputs.string }}
author: ${{ steps.committer.outputs.string }}
committer: ${{ steps.setup-bot.outputs.committer }}
author: ${{ steps.setup-bot.outputs.committer }}
signoff: true
branch: pre-commit
title: "🤖 format everything with pre-commit by <${{ steps.generate-token.outputs.app-slug }}>"
title: "🤖 format everything with pre-commit by ${{ steps.setup-bot.outputs.app-slug }}"
body: |
Auto-generated by [create-pull-request][1] with **${{ steps.generate-token.outputs.app-slug }}**
Auto-generated by [create-pull-request][1] with **${{ steps.setup-bot.outputs.app-slug }}**
[1]: https://github.com/peter-evans/create-pull-request
draft: false

View File

@ -16,44 +16,7 @@ permissions:
contents: read
jobs:
read_bot_entries:
runs-on: ubuntu-latest
outputs:
userName: ${{ steps.get-user-id.outputs.user_name }}
userEmail: ${{ steps.get-user-id.outputs.user_email }}
committer: ${{ steps.committer.outputs.committer }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Get GitHub App User ID
id: get-user-id
run: |
USER_NAME="${{ steps.generate-token.outputs.app-slug }}[bot]"
USER_ID=$(gh api "/users/$USER_NAME" --jq .id)
USER_EMAIL="$USER_ID+$USER_NAME@users.noreply.github.com"
echo "user_name=$USER_NAME" >> "$GITHUB_OUTPUT"
echo "user_email=$USER_EMAIL" >> "$GITHUB_OUTPUT"
echo "user-id=$USER_ID" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
- id: committer
run: |
COMMITTER="${{ steps.get-user-id.outputs.user_name }} <${{ steps.get-user-id.outputs.user_email }}>"
echo "committer=$COMMITTER" >> "$GITHUB_OUTPUT"
sync-files:
needs: ["read_bot_entries"]
runs-on: ubuntu-latest
steps:
- name: Harden Runner
@ -61,34 +24,29 @@ jobs:
with:
egress-policy: audit
- name: Generate GitHub App Token
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup GitHub App Bot
id: setup-bot
uses: ./.github/actions/setup-bot
with:
app-id: ${{ vars.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
cache: 'pip' # caching pip dependencies
cache: "pip" # caching pip dependencies
- name: Sync translation property files
run: |
python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
- name: Set up git config
run: |
git config --global user.name ${{ needs.read_bot_entries.outputs.userName }}
git config --global user.email ${{ needs.read_bot_entries.outputs.userEmail }}
- name: Run git add
- name: Commit translation files
run: |
git add src/main/resources/messages_*.properties
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes"
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "No changes detected"
- name: Install dependencies
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
@ -100,15 +58,16 @@ jobs:
- name: Run git add
run: |
git add README.md
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "no changes"
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "No changes detected"
- name: Create Pull Request
if: always()
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ steps.generate-token.outputs.token }}
token: ${{ steps.setup-bot.outputs.token }}
commit-message: Update files
committer: ${{ needs.read_bot_entries.outputs.committer }}
author: ${{ needs.read_bot_entries.outputs.committer }}
committer: ${{ steps.setup-bot.outputs.committer }}
author: ${{ steps.setup-bot.outputs.committer }}
signoff: true
branch: sync_readme
title: ":globe_with_meridians: Sync Translations + Update README Progress Table"

View File

@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.6
rev: v0.11.11
hooks:
- id: ruff
args:
@ -22,7 +22,7 @@ repos:
files: \.(html|css|js|py|md)$
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.3
rev: v8.26.0
hooks:
- id: gitleaks
- repo: https://github.com/pre-commit/pre-commit-hooks

View File

@ -10,7 +10,7 @@
"java.configuration.updateBuildConfiguration": "interactive",
"java.format.enabled": true,
"java.format.settings.profile": "GoogleStyle",
"java.format.settings.google.version": "1.26.0",
"java.format.settings.google.version": "1.27.0",
"java.format.settings.google.extra": "--aosp --skip-sorting-imports --skip-javadoc-formatting",
// (DE) Aktiviert Kommentare im Java-Format.
// (EN) Enables comments in Java formatting.

24
AGENTS.md Normal file
View File

@ -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.

View File

@ -128,7 +128,7 @@ Stirling-PDF currently supports 40 languages!
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![92%](https://geps.dev/progress/92) |
| German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
| German (Deutsch) (de_DE) | ![100%](https://geps.dev/progress/100) |
| Greek (Ελληνικά) (el_GR) | ![91%](https://geps.dev/progress/91) |
| Hindi (हिंदी) (hi_IN) | ![91%](https://geps.dev/progress/91) |
| Hungarian (Magyar) (hu_HU) | ![99%](https://geps.dev/progress/99) |
@ -143,9 +143,9 @@ Stirling-PDF currently supports 40 languages!
| Portuguese (Português) (pt_PT) | ![91%](https://geps.dev/progress/91) |
| Portuguese Brazilian (Português) (pt_BR) | ![97%](https://geps.dev/progress/97) |
| Romanian (Română) (ro_RO) | ![75%](https://geps.dev/progress/75) |
| Russian (Русский) (ru_RU) | ![93%](https://geps.dev/progress/93) |
| Russian (Русский) (ru_RU) | ![99%](https://geps.dev/progress/99) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![60%](https://geps.dev/progress/60) |
| Simplified Chinese (简体中文) (zh_CN) | ![93%](https://geps.dev/progress/93) |
| Simplified Chinese (简体中文) (zh_CN) | ![98%](https://geps.dev/progress/98) |
| Slovakian (Slovensky) (sk_SK) | ![69%](https://geps.dev/progress/69) |
| Slovenian (Slovenščina) (sl_SI) | ![94%](https://geps.dev/progress/94) |
| Spanish (Español) (es_ES) | ![99%](https://geps.dev/progress/99) |
@ -154,7 +154,7 @@ Stirling-PDF currently supports 40 languages!
| Tibetan (བོད་ཡིག་) (zh_BO) | ![88%](https://geps.dev/progress/88) |
| Traditional Chinese (繁體中文) (zh_TW) | ![99%](https://geps.dev/progress/99) |
| Turkish (Türkçe) (tr_TR) | ![97%](https://geps.dev/progress/97) |
| Ukrainian (Українська) (uk_UA) | ![96%](https://geps.dev/progress/96) |
| Ukrainian (Українська) (uk_UA) | ![99%](https://geps.dev/progress/99) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![73%](https://geps.dev/progress/73) |
| Malayalam (മലയാളം) (ml_ML) | ![99%](https://geps.dev/progress/99) |

View File

@ -1,7 +1,7 @@
plugins {
id "java"
id 'jacoco'
id "org.springframework.boot" version "3.4.5"
id "org.springframework.boot" version "3.5.0"
id "io.spring.dependency-management" version "1.1.7"
id "org.springdoc.openapi-gradle-plugin" version "1.9.0"
id "io.swagger.swaggerhub" version "1.3.2"
@ -19,7 +19,7 @@ import java.nio.file.Files
import java.time.Year
ext {
springBootVersion = "3.4.5"
springBootVersion = "3.5.0"
pdfboxVersion = "3.0.5"
imageioVersion = "3.12.0"
lombokVersion = "1.18.38"
@ -376,7 +376,7 @@ spotless {
java {
target project.fileTree('src').include('**/*.java')
googleJavaFormat("1.26.0").aosp().reorderImports(false)
googleJavaFormat("1.27.0").aosp().reorderImports(false)
importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
toggleOffOn()
@ -413,13 +413,14 @@ configurations.all {
// Exclude Tomcat
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
dependencies {
implementation project(':common')
//tmp for security bumps
implementation 'ch.qos.logback:logback-core:1.5.18'
implementation 'ch.qos.logback:logback-classic:1.5.18'
// Exclude vulnerable BouncyCastle version used in tableau
configurations.all {
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
@ -448,8 +449,6 @@ dependencies {
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
@ -458,7 +457,7 @@ dependencies {
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.session:spring-session-core:3.5.0"
implementation "org.springframework:spring-jdbc:6.2.7"
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
@ -544,9 +543,7 @@ dependencies {
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
// Mockito (core)
testImplementation 'org.mockito:mockito-core:5.17.0'
testImplementation 'org.mockito:mockito-core:5.18.0'
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
}

196
common/.gitignore vendored Normal file
View File

@ -0,0 +1,196 @@
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.exe
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
.classpath
.project
version.properties
#### Stirling-PDF Files ###
pipeline/watchedFolders/
pipeline/finishedFolders/
customFiles/
configs/
watchedFolders/
clientWebUI/
!cucumber/
!cucumber/exampleFiles/
!cucumber/exampleFiles/example_html.zip
exampleYmlFiles/stirling/
/testing/file_snapshots
SwaggerDoc.json
# Gradle
.gradle
.lock
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig
# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
*.db
/build
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*.pyo
# Virtual environments
.env*
.venv*
env*/
venv*/
ENV/
env.bak/
venv.bak/
# VS Code
/.vscode/**/*
!/.vscode/settings.json
!/.vscode/extensions.json
# IntelliJ IDEA
.idea/
*.iml
out/
# Ignore Mac DS_Store files
.DS_Store
**/.DS_Store
# cucumber
/cucumber/reports/**
# Certs and Security Files
*.p12
*.pk8
*.pem
*.crt
*.cer
*.cert
*.der
*.key
*.csr
*.kdbx
*.jks
*.asc
# SSH Keys
*.pub
*.priv
id_rsa
id_rsa.pub
id_ecdsa
id_ecdsa.pub
id_ed25519
id_ed25519.pub
.ssh/
*ssh
# cache
.cache
.ruff_cache
.mypy_cache
.pytest_cache
.ipynb_checkpoints
**/jcef-bundle/
# node_modules
node_modules/
*.mjs

52
common/build.gradle Normal file
View File

@ -0,0 +1,52 @@
plugins {
id 'java-library'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'stirling.software'
version = '0.46.2'
ext {
lombokVersion = "1.18.38"
}
java {
sourceCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
configurations.all {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
dependencyManagement {
imports {
mavenBom 'org.springframework.boot:spring-boot-dependencies:3.4.5'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
implementation 'com.fathzer:javaluator:3.0.6'
implementation 'com.posthog.java:posthog:1.2.0'
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
implementation 'org.apache.commons:commons-lang3:3.17.0'
implementation 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
implementation "org.apache.pdfbox:pdfbox:$pdfboxVersion"
implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6"
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testImplementation "org.springframework.boot:spring-boot-starter-test"
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import java.io.IOException;
import java.nio.file.Files;
@ -8,7 +8,9 @@ import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.function.Predicate;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -21,21 +23,29 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.spring6.SpringTemplateEngine;
import stirling.software.common.model.ApplicationProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
@Configuration
@Lazy
@Slf4j
@Configuration
@RequiredArgsConstructor
public class AppConfig {
private final Environment env;
private final ApplicationProperties applicationProperties;
private final Environment env;
@Getter
@Value("${baseUrl:http://localhost}")
private String baseUrl;
@Getter
@Value("${server.servlet.context-path:/}")
private String contextPath;
@Getter
@Value("${server.port:8080}")
private String serverPort;
@Bean
@ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true")
@ -198,6 +208,31 @@ public class AppConfig {
return applicationProperties.getAutomaticallyGenerated().getUUID();
}
@Bean
public ApplicationProperties.Security security() {
return applicationProperties.getSecurity();
}
@Bean
public ApplicationProperties.Security.OAUTH2 oAuth2() {
return applicationProperties.getSecurity().getOauth2();
}
@Bean
public ApplicationProperties.Premium premium() {
return applicationProperties.getPremium();
}
@Bean
public ApplicationProperties.System system() {
return applicationProperties.getSystem();
}
@Bean
public ApplicationProperties.Datasource datasource() {
return applicationProperties.getSystem().getDatasource();
}
@Bean(name = "disablePixel")
public boolean disablePixel() {
return Boolean.getBoolean(env.getProperty("DISABLE_PIXEL"));

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -13,6 +13,8 @@ import java.util.List;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.util.YamlHelper;
/**
* A naive, line-based approach to merging "settings.yml" with "settings.yml.template" while
* preserving exact whitespace, blank lines, and inline comments -- but we only rewrite the file if
@ -76,7 +78,7 @@ public class ConfigInitializer {
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
if (Files.notExists(customSettingsPath)) {
Files.createFile(customSettingsPath);
log.info("Created custom_settings file: {}", customSettingsPath.toString());
log.info("Created custom_settings file: {}", customSettingsPath);
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import java.io.IOException;
import java.io.InputStream;
@ -10,9 +10,11 @@ import org.thymeleaf.IEngineConfiguration;
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;
import stirling.software.common.model.InputStreamTemplateResource;
@Slf4j
public class FileFallbackTemplateResolver extends AbstractConfigurableTemplateResolver {
private final ResourceLoader resourceLoader;
@ -40,7 +42,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 =

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import java.io.File;
import java.nio.file.Paths;
@ -48,25 +48,22 @@ public class InstallationPathConfig {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return Paths.get(
System.getenv("APPDATA"), // parent path
"Stirling-PDF")
.toString()
+ File.separator;
System.getenv("APPDATA"), // parent path
"Stirling-PDF")
+ File.separator;
} else if (os.contains("mac")) {
return Paths.get(
System.getProperty("user.home"),
"Library",
"Application Support",
"Stirling-PDF")
.toString()
+ File.separator;
System.getProperty("user.home"),
"Library",
"Application Support",
"Stirling-PDF")
+ File.separator;
} else {
return Paths.get(
System.getProperty("user.home"), // parent path
".config",
"Stirling-PDF")
.toString()
+ File.separator;
System.getProperty("user.home"), // parent path
".config",
"Stirling-PDF")
+ File.separator;
}
}
return "." + File.separator;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import org.springframework.stereotype.Component;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import java.nio.file.Files;
import java.nio.file.Path;
@ -9,9 +9,9 @@ import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Operations;
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Pipeline;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.CustomPaths.Operations;
import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline;
@Slf4j
@Configuration

View File

@ -1,8 +1,6 @@
package stirling.software.SPDF.config;
package stirling.software.common.configuration;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
@ -12,8 +10,7 @@ import org.springframework.core.io.support.PropertySourceFactory;
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
throws IOException {
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();

View File

@ -0,0 +1,7 @@
package stirling.software.common.configuration.interfaces;
public interface ShowAdminInterface {
default boolean getShowUpdateOnlyAdmins() {
return true;
}
}

View File

@ -1,6 +1,4 @@
package stirling.software.SPDF.model;
import static stirling.software.SPDF.utils.validation.Validator.*;
package stirling.software.common.model;
import java.io.File;
import java.io.FileNotFoundException;
@ -14,10 +12,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
@ -26,54 +27,23 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.stereotype.Component;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.configuration.YamlPropertySourceFactory;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.common.model.oauth2.GitHubProvider;
import stirling.software.common.model.oauth2.GoogleProvider;
import stirling.software.common.model.oauth2.KeycloakProvider;
import stirling.software.common.model.oauth2.Provider;
import stirling.software.common.util.ValidationUtils;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.YamlPropertySourceFactory;
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
import stirling.software.SPDF.model.provider.GitHubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider;
import stirling.software.SPDF.model.provider.Provider;
@Configuration
@ConfigurationProperties(prefix = "")
@Data
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@ConfigurationProperties(prefix = "")
public class ApplicationProperties {
@Bean
public PropertySource<?> dynamicYamlPropertySource(ConfigurableEnvironment environment)
throws IOException {
String configPath = InstallationPathConfig.getSettingsPath();
log.debug("Attempting to load settings from: " + configPath);
File file = new File(configPath);
if (!file.exists()) {
log.error("Warning: Settings file does not exist at: " + configPath);
}
Resource resource = new FileSystemResource(configPath);
if (!resource.exists()) {
throw new FileNotFoundException("Settings file not found at: " + configPath);
}
EncodedResource encodedResource = new EncodedResource(resource);
PropertySource<?> propertySource =
new YamlPropertySourceFactory().createPropertySource(null, encodedResource);
environment.getPropertySources().addFirst(propertySource);
log.debug("Loaded properties: " + propertySource.getSource());
return propertySource;
}
private Legal legal = new Legal();
private Security security = new Security();
private System system = new System();
@ -89,6 +59,32 @@ public class ApplicationProperties {
private AutoPipeline autoPipeline = new AutoPipeline();
private ProcessExecutor processExecutor = new ProcessExecutor();
@Bean
public PropertySource<?> dynamicYamlPropertySource(ConfigurableEnvironment environment)
throws IOException {
String configPath = InstallationPathConfig.getSettingsPath();
log.debug("Attempting to load settings from: " + configPath);
File file = new File(configPath);
if (!file.exists()) {
log.error("Warning: Settings file does not exist at: " + configPath);
}
Resource resource = new FileSystemResource(configPath);
if (!resource.exists()) {
throw new FileNotFoundException("Settings file not found at: " + configPath);
}
EncodedResource encodedResource = new EncodedResource(resource);
PropertySource<?> propertySource =
new YamlPropertySourceFactory().createPropertySource(null, encodedResource);
environment.getPropertySources().addFirst(propertySource);
log.debug("Loaded properties: " + propertySource.getSource());
return propertySource;
}
@Data
public static class AutoPipeline {
private String outputFolder;
@ -248,11 +244,11 @@ public class ApplicationProperties {
}
public boolean isSettingsValid() {
return !isStringEmpty(this.getIssuer())
&& !isStringEmpty(this.getClientId())
&& !isStringEmpty(this.getClientSecret())
&& !isCollectionEmpty(this.getScopes())
&& !isStringEmpty(this.getUseAsUsername());
return !ValidationUtils.isStringEmpty(this.getIssuer())
&& !ValidationUtils.isStringEmpty(this.getClientId())
&& !ValidationUtils.isStringEmpty(this.getClientSecret())
&& !ValidationUtils.isCollectionEmpty(this.getScopes())
&& !ValidationUtils.isStringEmpty(this.getUseAsUsername());
}
@Data

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.model;
import java.nio.file.Path;
import java.nio.file.Paths;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.common.model;
import java.io.IOException;
import java.io.InputStream;
@ -39,7 +39,6 @@ public class InputStreamTemplateResource implements ITemplateResource {
@Override
public boolean exists() {
// TODO Auto-generated method stub
return false;
return inputStream != null;
}
}

View File

@ -0,0 +1,19 @@
package stirling.software.common.model;
import java.util.Calendar;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class PdfMetadata {
private String author;
private String producer;
private String title;
private String creator;
private String subject;
private String keywords;
private Calendar creationDate;
private Calendar modificationDate;
}

View File

@ -0,0 +1,19 @@
package stirling.software.common.model.api;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode
public class GeneralFile {
@Schema(
description = "The input file",
requiredMode = Schema.RequiredMode.REQUIRED,
format = "binary")
private MultipartFile fileInput;
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api;
package stirling.software.common.model.api;
import org.springframework.web.multipart.MultipartFile;

View File

@ -1,11 +1,10 @@
package stirling.software.SPDF.model.api.converters;
package stirling.software.common.model.api.converters;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.common.model.api.PDFFile;
@Data
@EqualsAndHashCode(callSuper = true)

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.misc;
package stirling.software.common.model.api.misc;
public enum HighContrastColorCombination {
WHITE_TEXT_ON_BLACK,

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.api.misc;
package stirling.software.common.model.api.misc;
public enum ReplaceAndInvert {
HIGH_CONTRAST_COLOR,

View File

@ -0,0 +1,28 @@
package stirling.software.common.model.api.security;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode
public class RedactionArea {
@Schema(description = "The left edge point of the area to be redacted.")
private Double x;
@Schema(description = "The top edge point of the area to be redacted.")
private Double y;
@Schema(description = "The height of the area to be redacted.")
private Double height;
@Schema(description = "The width of the area to be redacted.")
private Double width;
@Schema(description = "The page on which the area should be redacted.")
private Integer page;
@Schema(description = "The color used to redact the specified area.")
private String color;
}

View File

@ -0,0 +1,66 @@
package stirling.software.common.model.enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum Role {
// Unlimited access
ADMIN("ROLE_ADMIN", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.admin"),
// Unlimited access
USER("ROLE_USER", Integer.MAX_VALUE, Integer.MAX_VALUE, "adminUserSettings.user"),
// 40 API calls Per Day, 40 web calls
LIMITED_API_USER("ROLE_LIMITED_API_USER", 40, 40, "adminUserSettings.apiUser"),
// 20 API calls Per Day, 20 web calls
EXTRA_LIMITED_API_USER("ROLE_EXTRA_LIMITED_API_USER", 20, 20, "adminUserSettings.extraApiUser"),
// 0 API calls per day and 20 web calls
WEB_ONLY_USER("ROLE_WEB_ONLY_USER", 0, 20, "adminUserSettings.webOnlyUser"),
INTERNAL_API_USER(
"STIRLING-PDF-BACKEND-API-USER",
Integer.MAX_VALUE,
Integer.MAX_VALUE,
"adminUserSettings.internalApiUser"),
DEMO_USER("ROLE_DEMO_USER", 100, 100, "adminUserSettings.demoUser");
private final String roleId;
private final int apiCallsPerDay;
private final int webCallsPerDay;
private final String roleName;
public static String getRoleNameByRoleId(String roleId) {
// Using the fromString method to get the Role enum based on the roleId
Role role = fromString(roleId);
// Return the roleName of the found Role enum
return role.getRoleName();
}
// Method to retrieve all role IDs and role names
public static Map<String, String> getAllRoleDetails() {
// Using LinkedHashMap to preserve order
Map<String, String> roleDetails = new LinkedHashMap<>();
for (Role role : Role.values()) {
roleDetails.put(role.getRoleId(), role.getRoleName());
}
return roleDetails;
}
public static Role fromString(String roleId) {
for (Role role : Role.values()) {
if (role.getRoleId().equalsIgnoreCase(roleId)) {
return role;
}
}
throw new IllegalArgumentException("No Role defined for id: " + roleId);
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.common.model.enumeration;
import lombok.Getter;

View File

@ -0,0 +1,7 @@
package stirling.software.common.model.exception;
public class UnsupportedClaimException extends RuntimeException {
public UnsupportedClaimException(String message) {
super(message);
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.exception;
package stirling.software.common.model.exception;
public class UnsupportedProviderException extends Exception {
public UnsupportedProviderException(String message) {

View File

@ -1,11 +1,9 @@
package stirling.software.SPDF.model.provider;
package stirling.software.common.model.oauth2;
import java.util.ArrayList;
import java.util.Collection;
import lombok.NoArgsConstructor;
import stirling.software.SPDF.model.UsernameAttribute;
import stirling.software.common.model.enumeration.UsernameAttribute;
@NoArgsConstructor
public class GitHubProvider extends Provider {

View File

@ -1,11 +1,9 @@
package stirling.software.SPDF.model.provider;
package stirling.software.common.model.oauth2;
import java.util.ArrayList;
import java.util.Collection;
import lombok.NoArgsConstructor;
import stirling.software.SPDF.model.UsernameAttribute;
import stirling.software.common.model.enumeration.UsernameAttribute;
@NoArgsConstructor
public class GoogleProvider extends Provider {

View File

@ -1,11 +1,9 @@
package stirling.software.SPDF.model.provider;
package stirling.software.common.model.oauth2;
import java.util.ArrayList;
import java.util.Collection;
import lombok.NoArgsConstructor;
import stirling.software.SPDF.model.UsernameAttribute;
import stirling.software.common.model.enumeration.UsernameAttribute;
@NoArgsConstructor
public class KeycloakProvider extends Provider {

View File

@ -1,16 +1,13 @@
package stirling.software.SPDF.model.provider;
import static stirling.software.SPDF.model.UsernameAttribute.EMAIL;
package stirling.software.common.model.oauth2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import lombok.Data;
import lombok.NoArgsConstructor;
import stirling.software.SPDF.model.UsernameAttribute;
import stirling.software.SPDF.model.exception.UnsupportedUsernameAttribute;
import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.common.model.exception.UnsupportedClaimException;
import static stirling.software.common.model.enumeration.UsernameAttribute.EMAIL;
@Data
@NoArgsConstructor
@ -83,7 +80,7 @@ public class Provider {
return usernameAttribute;
}
default ->
throw new UnsupportedUsernameAttribute(
throw new UnsupportedClaimException(
String.format(EXCEPTION_MESSAGE, usernameAttribute, clientName));
}
}
@ -94,7 +91,7 @@ public class Provider {
return usernameAttribute;
}
default ->
throw new UnsupportedUsernameAttribute(
throw new UnsupportedClaimException(
String.format(EXCEPTION_MESSAGE, usernameAttribute, clientName));
}
}
@ -105,7 +102,7 @@ public class Provider {
return usernameAttribute;
}
default ->
throw new UnsupportedUsernameAttribute(
throw new UnsupportedClaimException(
String.format(EXCEPTION_MESSAGE, usernameAttribute, clientName));
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.service;
package stirling.software.common.service;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -22,7 +22,7 @@ import org.springframework.web.multipart.MultipartFile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.common.model.api.PDFFile;
/**
* Adaptive PDF document factory that optimizes memory usage based on file size and available system

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.service;
package stirling.software.common.service;
import java.util.Calendar;
@ -7,9 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.PdfMetadata;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.PdfMetadata;
@Service
public class PdfMetadataService {

View File

@ -1,12 +1,21 @@
package stirling.software.SPDF.service;
package stirling.software.common.service;
import java.io.File;
import java.lang.management.*;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -16,8 +25,7 @@ import org.springframework.stereotype.Service;
import com.posthog.java.PostHog;
import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties;
@Service
public class PostHogService {
@ -200,7 +208,7 @@ public class PostHogService {
// New environment variables
dockerMetrics.put("version_tag", System.getenv("VERSION_TAG"));
dockerMetrics.put("docker_enable_security", System.getenv("DOCKER_ENABLE_SECURITY"));
dockerMetrics.put("without_enhanced_features", System.getenv("WITHOUT_ENHANCED_FEATURES"));
dockerMetrics.put("fat_docker", System.getenv("FAT_DOCKER"));
return dockerMetrics;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api.pipeline;
package stirling.software.common.service;
public interface UserServiceInterface {
String getApiKeyForUser(String username);

View File

@ -1,10 +1,10 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
public class CheckProgramInstall {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.PrintWriter;
import java.io.StringWriter;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static java.nio.file.StandardWatchEventKinds.*;
@ -17,8 +17,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.common.configuration.RuntimePathConfig;
@Component
@Slf4j

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.*;
import java.nio.charset.StandardCharsets;
@ -16,8 +16,8 @@ import java.util.zip.ZipOutputStream;
import io.github.pixee.security.ZipSecurity;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.common.model.api.converters.HTMLToPdfRequest;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
public class FileToPdf {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.File;
import java.io.FileOutputStream;
@ -27,8 +27,7 @@ import io.github.pixee.security.Urls;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.YamlHelper;
import stirling.software.common.configuration.InstallationPathConfig;
@Slf4j
public class GeneralUtils {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.awt.geom.AffineTransform;
import java.awt.image.*;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -28,7 +28,7 @@ import io.github.pixee.security.Filenames;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
@Slf4j
@NoArgsConstructor

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.awt.*;
import java.awt.image.BufferedImage;
@ -34,8 +34,7 @@ import org.springframework.web.multipart.MultipartFile;
import io.github.pixee.security.Filenames;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.service.CustomPDFDocumentFactory;
import stirling.software.common.service.CustomPDFDocumentFactory;
@Slf4j
public class PdfUtils {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.BufferedReader;
import java.io.File;
@ -17,7 +17,7 @@ import io.github.pixee.security.BoundedLineReader;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties;
@Slf4j
public class ProcessExecutor {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.util.List;

View File

@ -1,10 +1,10 @@
package stirling.software.SPDF.utils.validation;
package stirling.software.common.util;
import java.util.Collection;
import stirling.software.common.model.oauth2.Provider;
import static stirling.software.common.util.ValidationUtils.isCollectionEmpty;
import static stirling.software.common.util.ValidationUtils.isStringEmpty;
import stirling.software.SPDF.model.provider.Provider;
public class Validator {
public class ProviderUtils {
public static boolean validateProvider(Provider provider) {
if (provider == null) {
@ -25,12 +25,4 @@ public class Validator {
return true;
}
public static boolean isStringEmpty(String input) {
return input == null || input.isBlank();
}
public static boolean isCollectionEmpty(Collection<String> input) {
return input == null || input.isEmpty();
}
}

View File

@ -1,14 +1,12 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
public class RequestUriUtils {
public static boolean isStaticResource(String requestURI) {
return isStaticResource("", requestURI);
}
public static boolean isStaticResource(String contextPath, String requestURI) {
return requestURI.startsWith(contextPath + "/css/")
|| requestURI.startsWith(contextPath + "/fonts/")
|| requestURI.startsWith(contextPath + "/js/")

View File

@ -1,9 +1,7 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.awt.*;
import javax.swing.*;
public class UIScaling {
private static final double BASE_RESOLUTION_WIDTH = 1920.0;
private static final double BASE_RESOLUTION_HEIGHT = 1080.0;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.IOException;
import java.net.ServerSocket;

View File

@ -0,0 +1,14 @@
package stirling.software.common.util;
import java.util.Collection;
public class ValidationUtils {
public static boolean isStringEmpty(String input) {
return input == null || input.isBlank();
}
public static boolean isCollectionEmpty(Collection<String> input) {
return input == null || input.isEmpty();
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.common.util;
import java.io.IOException;
import java.io.StringWriter;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import java.awt.*;
import java.io.ByteArrayInputStream;
@ -23,9 +23,8 @@ import org.springframework.core.io.InputStreamResource;
import org.springframework.web.multipart.MultipartFile;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
@Slf4j
public class CustomColorReplaceStrategy extends ReplaceAndInvertColorStrategy {

View File

@ -1,7 +1,7 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
public class HighContrastColorReplaceDecider {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import java.awt.*;
import java.awt.image.BufferedImage;
@ -18,8 +18,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.core.io.InputStreamResource;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
public class InvertFullColorStrategy extends ReplaceAndInvertColorStrategy {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import java.awt.geom.Rectangle2D;
import java.io.IOException;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import java.io.IOException;
@ -8,8 +8,8 @@ import org.springframework.web.multipart.MultipartFile;
import lombok.Data;
import lombok.EqualsAndHashCode;
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
@Data
@EqualsAndHashCode(callSuper = true)

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.propertyeditor;
package stirling.software.common.util.propertyeditor;
import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
@ -9,8 +9,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.security.RedactionArea;
import stirling.software.common.model.api.security.RedactionArea;
@Slf4j
public class StringToArrayListPropertyEditor extends PropertyEditorSupport {
@ -26,7 +25,8 @@ public class StringToArrayListPropertyEditor extends PropertyEditorSupport {
try {
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
TypeReference<ArrayList<RedactionArea>> typeRef =
new TypeReference<ArrayList<RedactionArea>>() {};
new TypeReference<>() {
};
List<RedactionArea> list = objectMapper.readValue(text, typeRef);
setValue(list);
} catch (Exception e) {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.propertyeditor;
package stirling.software.common.util.propertyeditor;
import java.beans.PropertyEditorSupport;
import java.util.HashMap;
@ -15,7 +15,7 @@ public class StringToMapPropertyEditor extends PropertyEditorSupport {
public void setAsText(String text) throws IllegalArgumentException {
try {
TypeReference<HashMap<String, String>> typeRef =
new TypeReference<HashMap<String, String>>() {};
new TypeReference<>() {};
Map<String, String> map = objectMapper.readValue(text, typeRef);
setValue(map);
} catch (Exception e) {

View File

@ -1,18 +1,18 @@
package stirling.software.SPDF.service;
package stirling.software.common.service;
import java.nio.file.Files;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static stirling.software.common.service.SpyPDFDocumentFactory.*;
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;
@ -20,12 +20,11 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.mock.web.MockMultipartFile;
import stirling.software.SPDF.model.api.PDFFile;
import stirling.software.SPDF.service.SpyPDFDocumentFactory.StrategyType;
import stirling.software.common.model.api.PDFFile;
@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,76 +42,53 @@ 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)) {
assertEquals(expected, factory.lastStrategyUsed);
Assertions.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_ByteArray(int sizeMB, StrategyType expected) throws IOException {
byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
try (PDDocument doc = factory.load(inflated)) {
assertEquals(expected, factory.lastStrategyUsed);
Assertions.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_InputStream(int sizeMB, StrategyType expected) throws IOException {
byte[] inflated = inflatePdf(basePdfBytes, sizeMB);
try (PDDocument doc = factory.load(new ByteArrayInputStream(inflated))) {
assertEquals(expected, factory.lastStrategyUsed);
Assertions.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_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);
Assertions.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)) {
assertEquals(expected, factory.lastStrategyUsed);
Assertions.assertEquals(expected, factory.lastStrategyUsed);
}
}
@ -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();
}
}

View File

@ -1,14 +1,14 @@
package stirling.software.SPDF.service;
package stirling.software.common.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
}
}
}

View File

@ -1,5 +1,15 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -10,19 +20,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
class CheckProgramInstallTest {
private MockedStatic<ProcessExecutor> mockProcessExecutor;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -27,25 +27,28 @@ class CustomHtmlSanitizerTest {
private static Stream<Arguments> provideHtmlTestCases() {
return Stream.of(
Arguments.of(
"<p>This is <strong>valid</strong> HTML with <em>formatting</em>.</p>",
new String[] {"<p>", "<strong>", "<em>"}
),
Arguments.of(
"<p>Text with <b>bold</b>, <i>italic</i>, <u>underline</u>, "
+ "<em>emphasis</em>, <strong>strong</strong>, <strike>strikethrough</strike>, "
+ "<s>strike</s>, <sub>subscript</sub>, <sup>superscript</sup>, "
+ "<tt>teletype</tt>, <code>code</code>, <big>big</big>, <small>small</small>.</p>",
new String[] {"<b>bold</b>", "<i>italic</i>", "<em>emphasis</em>", "<strong>strong</strong>"}
),
Arguments.of(
"<div>Division</div><h1>Heading 1</h1><h2>Heading 2</h2><h3>Heading 3</h3>"
+ "<h4>Heading 4</h4><h5>Heading 5</h5><h6>Heading 6</h6>"
+ "<blockquote>Blockquote</blockquote><ul><li>List item</li></ul>"
+ "<ol><li>Ordered item</li></ol>",
new String[] {"<div>", "<h1>", "<h6>", "<blockquote>", "<ul>", "<ol>", "<li>"}
)
);
Arguments.of(
"<p>This is <strong>valid</strong> HTML with <em>formatting</em>.</p>",
new String[] {"<p>", "<strong>", "<em>"}),
Arguments.of(
"<p>Text with <b>bold</b>, <i>italic</i>, <u>underline</u>, "
+ "<em>emphasis</em>, <strong>strong</strong>, <strike>strikethrough</strike>, "
+ "<s>strike</s>, <sub>subscript</sub>, <sup>superscript</sup>, "
+ "<tt>teletype</tt>, <code>code</code>, <big>big</big>, <small>small</small>.</p>",
new String[] {
"<b>bold</b>",
"<i>italic</i>",
"<em>emphasis</em>",
"<strong>strong</strong>"
}),
Arguments.of(
"<div>Division</div><h1>Heading 1</h1><h2>Heading 2</h2><h3>Heading 3</h3>"
+ "<h4>Heading 4</h4><h5>Heading 5</h5><h6>Heading 6</h6>"
+ "<blockquote>Blockquote</blockquote><ul><li>List item</li></ul>"
+ "<ol><li>Ordered item</li></ol>",
new String[] {
"<div>", "<h1>", "<h6>", "<blockquote>", "<ul>", "<ol>", "<li>"
}));
}
@Test

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -7,6 +7,8 @@ import java.time.LocalDateTime;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import stirling.software.common.model.FileInfo;
public class FileInfoTest {
@ParameterizedTest(name = "{index}: fileSize={0}")

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -19,8 +19,7 @@ import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.SPDF.config.RuntimePathConfig;
import stirling.software.common.configuration.RuntimePathConfig;
@ExtendWith(MockitoExtension.class)
class FileMonitorTest {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -8,7 +8,7 @@ import java.io.IOException;
import org.junit.jupiter.api.Test;
import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
import stirling.software.common.model.api.converters.HTMLToPdfRequest;
public class FileToPdfTest {

View File

@ -0,0 +1,41 @@
package stirling.software.common.util;
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"));
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,6 +1,5 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
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,7 +28,9 @@ import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;
import io.github.pixee.security.ZipSecurity;
import stirling.software.common.util.ProcessExecutor.ProcessExecutorResult;
/**
* Tests for PDFToFile utility class. This includes both invalid content type cases and positive
@ -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;

View File

@ -0,0 +1,125 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
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;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.service.PdfMetadataService;
public class PdfUtilsTest {
@Test
void testTextToPageSize() {
assertEquals(PDRectangle.A4, PdfUtils.textToPageSize("A4"));
assertEquals(PDRectangle.LETTER, PdfUtils.textToPageSize("LETTER"));
assertThrows(IllegalArgumentException.class, () -> PdfUtils.textToPageSize("INVALID"));
}
@Test
void testHasImagesOnPage() throws IOException {
// Mock a PDPage and its resources
PDPage page = Mockito.mock(PDPage.class);
PDResources resources = Mockito.mock(PDResources.class);
Mockito.when(page.getResources()).thenReturn(resources);
// Case 1: No images in resources
Mockito.when(resources.getXObjectNames()).thenReturn(Collections.emptySet());
assertFalse(PdfUtils.hasImagesOnPage(page));
// Case 2: Resources with an image
Set<COSName> xObjectNames = new HashSet<>();
COSName cosName = Mockito.mock(COSName.class);
xObjectNames.add(cosName);
PDImageXObject imageXObject = Mockito.mock(PDImageXObject.class);
Mockito.when(resources.getXObjectNames()).thenReturn(xObjectNames);
Mockito.when(resources.getXObject(cosName)).thenReturn(imageXObject);
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());
}
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@ -1,27 +1,22 @@
package stirling.software.SPDF.utils.validation;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
package stirling.software.common.util;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.SPDF.model.UsernameAttribute;
import stirling.software.SPDF.model.provider.GitHubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.Provider;
import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.common.model.oauth2.GitHubProvider;
import stirling.software.common.model.oauth2.GoogleProvider;
import stirling.software.common.model.oauth2.Provider;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class ValidatorTest {
class ProviderUtilsTest {
@Test
void testSuccessfulValidation() {
@ -31,13 +26,13 @@ class ValidatorTest {
when(provider.getClientSecret()).thenReturn("clientSecret");
when(provider.getScopes()).thenReturn(List.of("read:user"));
assertTrue(Validator.validateProvider(provider));
Assertions.assertTrue(ProviderUtils.validateProvider(provider));
}
@ParameterizedTest
@MethodSource("providerParams")
void testUnsuccessfulValidation(Provider provider) {
assertFalse(Validator.validateProvider(provider));
Assertions.assertFalse(ProviderUtils.validateProvider(provider));
}
public static Stream<Arguments> providerParams() {

View File

@ -0,0 +1,311 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class RequestUriUtilsTest {
@Test
void testIsStaticResource() {
// Test static resources without context path
assertTrue(
RequestUriUtils.isStaticResource("/css/styles.css"), "CSS files should be static");
assertTrue(RequestUriUtils.isStaticResource("/js/script.js"), "JS files should be static");
assertTrue(
RequestUriUtils.isStaticResource("/images/logo.png"),
"Image files should be static");
assertTrue(
RequestUriUtils.isStaticResource("/public/index.html"),
"Public files should be static");
assertTrue(
RequestUriUtils.isStaticResource("/pdfjs/pdf.worker.js"),
"PDF.js files should be static");
assertTrue(
RequestUriUtils.isStaticResource("/api/v1/info/status"),
"API status should be static");
assertTrue(
RequestUriUtils.isStaticResource("/some-path/icon.svg"),
"SVG files should be static");
assertTrue(RequestUriUtils.isStaticResource("/login"), "Login page should be static");
assertTrue(RequestUriUtils.isStaticResource("/error"), "Error page should be static");
// Test non-static resources
assertFalse(
RequestUriUtils.isStaticResource("/api/v1/users"),
"API users should not be static");
assertFalse(
RequestUriUtils.isStaticResource("/api/v1/orders"),
"API orders should not be static");
assertFalse(RequestUriUtils.isStaticResource("/"), "Root path should not be static");
assertFalse(
RequestUriUtils.isStaticResource("/register"),
"Register page should not be static");
assertFalse(
RequestUriUtils.isStaticResource("/api/v1/products"),
"API products should not be static");
}
@Test
void testIsStaticResourceWithContextPath() {
String contextPath = "/myapp";
// Test static resources with context path
assertTrue(
RequestUriUtils.isStaticResource(contextPath, contextPath + "/css/styles.css"),
"CSS with context path should be static");
assertTrue(
RequestUriUtils.isStaticResource(contextPath, contextPath + "/js/script.js"),
"JS with context path should be static");
assertTrue(
RequestUriUtils.isStaticResource(contextPath, contextPath + "/images/logo.png"),
"Images with context path should be static");
assertTrue(
RequestUriUtils.isStaticResource(contextPath, contextPath + "/login"),
"Login with context path should be static");
// Test non-static resources with context path
assertFalse(
RequestUriUtils.isStaticResource(contextPath, contextPath + "/api/v1/users"),
"API users with context path should not be static");
assertFalse(
RequestUriUtils.isStaticResource(contextPath, "/"),
"Root path with context path should not be static");
}
@ParameterizedTest
@ValueSource(
strings = {
"robots.txt",
"/favicon.ico",
"/icon.svg",
"/image.png",
"/site.webmanifest",
"/app/logo.svg",
"/downloads/document.png",
"/assets/brand.ico",
"/any/path/with/image.svg",
"/deep/nested/folder/icon.png"
})
void testIsStaticResourceWithFileExtensions(String path) {
assertTrue(
RequestUriUtils.isStaticResource(path),
"Files with specific extensions should be static regardless of path");
}
@Test
void testIsTrackableResource() {
// Test non-trackable resources (returns false)
assertFalse(
RequestUriUtils.isTrackableResource("/js/script.js"),
"JS files should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/v1/api-docs"),
"API docs should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("robots.txt"),
"robots.txt should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/images/logo.png"),
"Images should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/styles.css"),
"CSS files should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/script.js.map"),
"Map files should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/icon.svg"),
"SVG files should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/popularity.txt"),
"Popularity file should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/script.js"),
"JS files should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/swagger/index.html"),
"Swagger files should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/api/v1/info/status"),
"API info should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/site.webmanifest"),
"Webmanifest should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/fonts/font.woff"),
"Fonts should not be trackable");
assertFalse(
RequestUriUtils.isTrackableResource("/pdfjs/viewer.js"),
"PDF.js files should not be trackable");
// Test trackable resources (returns true)
assertTrue(RequestUriUtils.isTrackableResource("/login"), "Login page should be trackable");
assertTrue(
RequestUriUtils.isTrackableResource("/register"),
"Register page should be trackable");
assertTrue(
RequestUriUtils.isTrackableResource("/api/v1/users"),
"API users should be trackable");
assertTrue(RequestUriUtils.isTrackableResource("/"), "Root path should be trackable");
assertTrue(
RequestUriUtils.isTrackableResource("/some-other-path"),
"Other paths should be trackable");
}
@Test
void testIsTrackableResourceWithContextPath() {
String contextPath = "/myapp";
// Test with context path
assertFalse(
RequestUriUtils.isTrackableResource(contextPath, "/js/script.js"),
"JS files should not be trackable with context path");
assertTrue(
RequestUriUtils.isTrackableResource(contextPath, "/login"),
"Login page should be trackable with context path");
// Additional tests with context path
assertFalse(
RequestUriUtils.isTrackableResource(contextPath, "/fonts/custom.woff"),
"Font files should not be trackable with context path");
assertFalse(
RequestUriUtils.isTrackableResource(contextPath, "/images/header.png"),
"Images should not be trackable with context path");
assertFalse(
RequestUriUtils.isTrackableResource(contextPath, "/swagger/ui.html"),
"Swagger UI should not be trackable with context path");
assertTrue(
RequestUriUtils.isTrackableResource(contextPath, "/account/profile"),
"Account page should be trackable with context path");
assertTrue(
RequestUriUtils.isTrackableResource(contextPath, "/pdf/view"),
"PDF view page should be trackable with context path");
}
@ParameterizedTest
@ValueSource(
strings = {
"/js/util.js",
"/v1/api-docs/swagger.json",
"/robots.txt",
"/images/header/logo.png",
"/styles/theme.css",
"/build/app.js.map",
"/assets/icon.svg",
"/data/popularity.txt",
"/bundle.js",
"/api/swagger-ui.html",
"/api/v1/info/health",
"/site.webmanifest",
"/fonts/roboto.woff",
"/pdfjs/viewer.js"
})
void testNonTrackableResources(String path) {
assertFalse(
RequestUriUtils.isTrackableResource(path),
"Resources matching patterns should not be trackable: " + path);
}
@ParameterizedTest
@ValueSource(
strings = {
"/",
"/home",
"/login",
"/register",
"/pdf/merge",
"/pdf/split",
"/api/v1/users/1",
"/api/v1/documents/process",
"/settings",
"/account/profile",
"/dashboard",
"/help",
"/about"
})
void testTrackableResources(String path) {
assertTrue(
RequestUriUtils.isTrackableResource(path),
"App routes should be trackable: " + path);
}
@Test
void testEdgeCases() {
// Test with empty strings
assertFalse(RequestUriUtils.isStaticResource("", ""), "Empty path should not be static");
assertTrue(RequestUriUtils.isTrackableResource("", ""), "Empty path should be trackable");
// Test with null-like behavior (would actually throw NPE in real code)
// These are not actual null tests but shows handling of odd cases
assertFalse(RequestUriUtils.isStaticResource("null"), "String 'null' should not be static");
// Test String "null" as a path
boolean isTrackable = RequestUriUtils.isTrackableResource("null");
assertTrue(isTrackable, "String 'null' should be trackable");
// Mixed case extensions test - note that Java's endsWith() is case-sensitive
// We'll check actual behavior and document it rather than asserting
// Always test the lowercase versions which should definitely work
assertTrue(
RequestUriUtils.isStaticResource("/logo.png"), "PNG (lowercase) should be static");
assertTrue(
RequestUriUtils.isStaticResource("/icon.svg"), "SVG (lowercase) should be static");
// Path with query parameters
assertFalse(
RequestUriUtils.isStaticResource("/api/users?page=1"),
"Path with query params should respect base path");
assertTrue(
RequestUriUtils.isStaticResource("/images/logo.png?v=123"),
"Static resource with query params should still be static");
// Paths with fragments
assertTrue(
RequestUriUtils.isStaticResource("/css/styles.css#section1"),
"CSS with fragment should be static");
// Multiple dots in filename
assertTrue(
RequestUriUtils.isStaticResource("/js/jquery.min.js"),
"JS with multiple dots should be static");
// Special characters in path
assertTrue(
RequestUriUtils.isStaticResource("/images/user's-photo.png"),
"Path with special chars should be handled correctly");
}
@Test
void testComplexPaths() {
// Test complex static resource paths
assertTrue(
RequestUriUtils.isStaticResource("/css/theme/dark/styles.css"),
"Nested CSS should be static");
assertTrue(
RequestUriUtils.isStaticResource("/fonts/open-sans/bold/font.woff"),
"Nested font should be static");
assertTrue(
RequestUriUtils.isStaticResource("/js/vendor/jquery/3.5.1/jquery.min.js"),
"Versioned JS should be static");
// Test complex paths with context
String contextPath = "/app";
assertTrue(
RequestUriUtils.isStaticResource(
contextPath, contextPath + "/css/theme/dark/styles.css"),
"Nested CSS with context should be static");
// Test boundary cases for isTrackableResource
assertFalse(
RequestUriUtils.isTrackableResource("/js-framework/components"),
"Path starting with js- should not be treated as JS resource");
assertFalse(
RequestUriUtils.isTrackableResource("/fonts-selection"),
"Path starting with fonts- should not be treated as font resource");
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils;
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -11,8 +11,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
class CustomColorReplaceStrategyTest {

View File

@ -1,12 +1,10 @@
package stirling.software.SPDF.utils.misc;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
package stirling.software.common.util.misc;
import org.junit.jupiter.api.Test;
import stirling.software.SPDF.model.api.misc.HighContrastColorCombination;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
class HighContrastColorReplaceDeciderTest {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -26,8 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.io.InputStreamResource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
class InvertFullColorStrategyTest {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.misc;
package stirling.software.common.util.misc;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -9,8 +9,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.io.InputStreamResource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import stirling.software.SPDF.model.api.misc.ReplaceAndInvert;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
class ReplaceAndInvertColorStrategyTest {

View File

@ -1,17 +1,14 @@
package stirling.software.SPDF.utils.propertyeditor;
package stirling.software.common.util.propertyeditor;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import stirling.software.common.model.api.security.RedactionArea;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import stirling.software.SPDF.model.api.security.RedactionArea;
class StringToArrayListPropertyEditorTest {
private StringToArrayListPropertyEditor editor;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.utils.propertyeditor;
package stirling.software.common.util.propertyeditor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -3,3 +3,5 @@ plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
}
rootProject.name = 'Stirling-PDF'
include 'common'

View File

@ -8,10 +8,10 @@ import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition;
import stirling.software.SPDF.model.ApplicationProperties.Premium;
import stirling.software.SPDF.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.EnterpriseEdition;
import stirling.software.common.model.ApplicationProperties.Premium;
import stirling.software.common.model.ApplicationProperties.Premium.ProFeatures.GoogleDrive;
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)

View File

@ -19,8 +19,8 @@ import com.posthog.java.shaded.org.json.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.util.GeneralUtils;
@Service
@Slf4j
@ -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<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
HttpResponse<String> 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<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
HttpResponse<String> 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<String> 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<String> 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<String> 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<String> 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) {

Some files were not shown because too many files have changed in this diff Show More