Compare commits

..

1 Commits

Author SHA1 Message Date
stirlingbot[bot]
ba4be0ae23
Update 3rd Party Licenses
Signed-off-by: stirlingbot[bot] <stirlingbot[bot]@users.noreply.github.com>
2025-06-05 11:30:11 +00:00
924 changed files with 7578 additions and 4992 deletions

14
.gitattributes vendored
View File

@ -1,10 +1,10 @@
* text=auto eol=lf * text=auto eol=lf
# Ignore all JavaScript files in a directory # Ignore all JavaScript files in a directory
stirling-pdf/src/main/resources/static/pdfjs/* linguist-vendored src/main/resources/static/pdfjs/* linguist-vendored
stirling-pdf/src/main/resources/static/pdfjs/** linguist-vendored src/main/resources/static/pdfjs/** linguist-vendored
stirling-pdf/src/main/resources/static/pdfjs-legacy/* linguist-vendored src/main/resources/static/pdfjs-legacy/* linguist-vendored
stirling-pdf/src/main/resources/static/pdfjs-legacy/** linguist-vendored src/main/resources/static/pdfjs-legacy/** linguist-vendored
stirling-pdf/src/main/resources/static/css/bootstrap-icons.css linguist-vendored src/main/resources/static/css/bootstrap-icons.css linguist-vendored
stirling-pdf/src/main/resources/static/css/bootstrap.min.css linguist-vendored src/main/resources/static/css/bootstrap.min.css linguist-vendored
stirling-pdf/src/main/resources/static/css/fonts/* linguist-vendored src/main/resources/static/css/fonts/* linguist-vendored

View File

@ -1,45 +1,60 @@
Translation: Translation:
- changed-files: - changed-files:
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/messages_*_*.properties' - any-glob-to-any-file: 'src/main/resources/messages_*_*.properties'
- any-glob-to-any-file: 'scripts/ignore_translation.toml' - any-glob-to-any-file: 'scripts/ignore_translation.toml'
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/templates/fragments/languages.html' - any-glob-to-any-file: 'src/main/resources/templates/fragments/languages.html'
Front End: Front End:
- changed-files: - changed-files:
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/templates/**/*' - any-glob-to-any-file: 'src/main/resources/templates/**/*'
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/static/**/*' - any-glob-to-any-file: 'src/main/resources/static/**/*'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/**' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/**'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/UI/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/UI/**/*'
Java: Java:
- changed-files: - changed-files:
- any-glob-to-any-file: 'common/src/main/java/**/*.java' - any-glob-to-any-file: 'src/main/java/**/*.java'
- any-glob-to-any-file: 'proprietary/src/main/java/**/*.java'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/**/*.java'
Back End: Back End:
- changed-files: - changed-files:
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/config/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/**/*'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/**/*'
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/settings.yml.template' - any-glob-to-any-file: 'src/main/resources/settings.yml.template'
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/application.properties' - any-glob-to-any-file: 'src/main/resources/application.properties'
- any-glob-to-any-file: 'stirling-pdf/src/main/resources/banner.txt' - any-glob-to-any-file: 'src/main/resources/banner.txt'
- any-glob-to-any-file: 'scripts/png_to_webp.py' - any-glob-to-any-file: 'scripts/png_to_webp.py'
- any-glob-to-any-file: 'split_photos.py' - any-glob-to-any-file: 'split_photos.py'
Security: Security:
- changed-files: - changed-files:
- any-glob-to-any-file: 'proprietary/src/main/java/stirling/software/proprietary/security/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/interfaces/DatabaseInterface.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/DatabaseController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/EmailController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/H2SQLController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/DatabaseWebController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/UserController.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/api/Email.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/exception/BackupNotFoundException.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/exception/NoProviderFoundExceptionjava'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/provider/**/*'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AuthenticationType.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/ApiKeyAuthenticationToken.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AttemptCounter.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/Authority.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/PersistentLogin.java'
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/SessionEntity.java'
- any-glob-to-any-file: 'scripts/download-security-jar.sh' - any-glob-to-any-file: 'scripts/download-security-jar.sh'
- any-glob-to-any-file: '.github/workflows/dependency-review.yml' - any-glob-to-any-file: '.github/workflows/dependency-review.yml'
- any-glob-to-any-file: '.github/workflows/scorecards.yml' - any-glob-to-any-file: '.github/workflows/scorecards.yml'
API: API:
- changed-files: - changed-files:
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/config/OpenApiConfig.java' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/OpenApiConfig.java'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/MetricsController.java'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/api/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/**/*'
- any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/model/api/**/*' - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/api/**/*'
- any-glob-to-any-file: 'scripts/png_to_webp.py' - any-glob-to-any-file: 'scripts/png_to_webp.py'
- any-glob-to-any-file: 'split_photos.py' - any-glob-to-any-file: 'split_photos.py'
- any-glob-to-any-file: '.github/workflows/swagger.yml' - any-glob-to-any-file: '.github/workflows/swagger.yml'
@ -73,9 +88,7 @@ Devtools:
Test: Test:
- changed-files: - changed-files:
- any-glob-to-any-file: 'cucumber/**/*' - any-glob-to-any-file: 'cucumber/**/*'
- any-glob-to-any-file: 'common/src/test/**/*' - any-glob-to-any-file: 'src/test/**/*'
- any-glob-to-any-file: 'proprietary/src/test/**/*'
- any-glob-to-any-file: 'stirling-pdf/src/test/**/*'
- any-glob-to-any-file: 'src/testing/**/*' - any-glob-to-any-file: 'src/testing/**/*'
- any-glob-to-any-file: '.pre-commit-config' - any-glob-to-any-file: '.pre-commit-config'
- any-glob-to-any-file: '.github/workflows/pre_commit.yml' - any-glob-to-any-file: '.github/workflows/pre_commit.yml'

View File

@ -317,7 +317,7 @@ def check_for_differences(reference_file, file_list, branch, actor):
report.append("## ❌ Overall Check Status: **_Failed_**") report.append("## ❌ Overall Check Status: **_Failed_**")
report.append("") report.append("")
report.append( report.append(
f"@{actor} please check your translation if it conforms to the standard. Follow the format of [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/stirling-pdf/src/main/resources/messages_en_GB.properties)" f"@{actor} please check your translation if it conforms to the standard. Follow the format of [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties)"
) )
else: else:
report.append("## ✅ Overall Check Status: **_Success_**") report.append("## ✅ Overall Check Status: **_Success_**")

View File

@ -4,7 +4,7 @@ on:
pull_request_target: pull_request_target:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
paths: paths:
- "stirling-pdf/src/main/resources/messages_*.properties" - "src/main/resources/messages_*.properties"
permissions: permissions:
contents: read # Allow read access to repository content contents: read # Allow read access to repository content
@ -61,20 +61,7 @@ jobs:
run: | run: |
echo "Fetching PR changed files..." echo "Fetching PR changed files..."
echo "Getting list of changed files from PR..." echo "Getting list of changed files from PR..."
# Check if PR number exists gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt # Filter only matching property files
if [ -z "${{ steps.get-pr-data.outputs.pr_number }}" ]; then
echo "Error: PR number is empty"
exit 1
fi
# Get changed files and filter for properties files, handle case where no matches are found
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^stirling-pdf/src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt || echo "No matching properties files found in PR"
# Check if any files were found
if [ ! -s changed_files.txt ]; then
echo "No properties files changed in this PR"
echo "Workflow will exit early as no relevant files to check"
exit 0
fi
echo "Found $(wc -l < changed_files.txt) matching properties files"
- name: Determine reference file test - name: Determine reference file test
id: determine-file id: determine-file
@ -116,7 +103,7 @@ jobs:
// Filter for relevant files based on the PR changes // Filter for relevant files based on the PR changes
const changedFiles = files const changedFiles = files
.map(file => file.filename) .map(file => file.filename)
.filter(file => /^stirling-pdf\src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file)); .filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file));
console.log("Changed files:", changedFiles); console.log("Changed files:", changedFiles);
@ -154,12 +141,12 @@ jobs:
// Determine reference file // Determine reference file
let referenceFilePath; let referenceFilePath;
if (changedFiles.includes("stirling-pdf/src/main/resources/messages_en_GB.properties")) { if (changedFiles.includes("src/main/resources/messages_en_GB.properties")) {
console.log("Using PR branch reference file."); console.log("Using PR branch reference file.");
const { data: fileContent } = await github.rest.repos.getContent({ const { data: fileContent } = await github.rest.repos.getContent({
owner: prRepoOwner, owner: prRepoOwner,
repo: prRepoName, repo: prRepoName,
path: "stirling-pdf/src/main/resources/messages_en_GB.properties", path: "src/main/resources/messages_en_GB.properties",
ref: branch, ref: branch,
}); });
@ -171,7 +158,7 @@ jobs:
const { data: fileContent } = await github.rest.repos.getContent({ const { data: fileContent } = await github.rest.repos.getContent({
owner: repoOwner, owner: repoOwner,
repo: repoName, repo: repoName,
path: "stirling-pdf/src/main/resources/messages_en_GB.properties", path: "src/main/resources/messages_en_GB.properties",
ref: "main", ref: "main",
}); });

View File

@ -57,11 +57,11 @@ jobs:
- name: Move and rename license file - name: Move and rename license file
run: | run: |
mv build/reports/dependency-license/index.json stirling-pdf/src/main/resources/static/3rdPartyLicenses.json mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json
- name: Commit changes - name: Commit changes
run: | run: |
git add stirling-pdf/src/main/resources/static/3rdPartyLicenses.json git add src/main/resources/static/3rdPartyLicenses.json
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
- name: Create Pull Request - name: Create Pull Request

View File

@ -8,8 +8,8 @@ on:
paths: paths:
- "build.gradle" - "build.gradle"
- "README.md" - "README.md"
- "stirling-pdf/src/main/resources/messages_*.properties" - "src/main/resources/messages_*.properties"
- "stirling-pdf/src/main/resources/static/3rdPartyLicenses.json" - "src/main/resources/static/3rdPartyLicenses.json"
- "scripts/ignore_translation.toml" - "scripts/ignore_translation.toml"
permissions: permissions:
@ -41,11 +41,11 @@ jobs:
- name: Sync translation property files - name: Sync translation property files
run: | run: |
python .github/scripts/check_language_properties.py --reference-file "stirling-pdf/src/main/resources/messages_en_GB.properties" --branch main python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
- name: Commit translation files - name: Commit translation files
run: | run: |
git add stirling-pdf/src/main/resources/messages_*.properties git add src/main/resources/messages_*.properties
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "No changes detected" git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "No changes detected"
- name: Install dependencies - name: Install dependencies
@ -101,4 +101,4 @@ jobs:
sign-commits: true sign-commits: true
add-paths: | add-paths: |
README.md README.md
stirling-pdf/src/main/resources/messages_*.properties src/main/resources/messages_*.properties

4
.gitignore vendored
View File

@ -125,9 +125,6 @@ SwaggerDoc.json
*.rar *.rar
*.db *.db
/build /build
/stirling-pdf/build
/common/build
/proprietary/build
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
@ -197,3 +194,4 @@ id_ed25519.pub
# node_modules # node_modules
node_modules/ node_modules/
*.mjs

View File

@ -20,7 +20,7 @@ repos:
- --skip="./.*,*.csv,*.json,*.ambr" - --skip="./.*,*.csv,*.json,*.ambr"
- --quiet-level=2 - --quiet-level=2
files: \.(html|css|js|py|md)$ files: \.(html|css|js|py|md)$
exclude: (.vscode|.devcontainer|stirling-pdf/src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js) exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
- repo: https://github.com/gitleaks/gitleaks - repo: https://github.com/gitleaks/gitleaks
rev: v8.26.0 rev: v8.26.0
hooks: hooks:

View File

@ -137,9 +137,9 @@ services:
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DISABLE_ADDITIONAL_FEATURES: "false" DISABLE_ADDITIONAL_FEATURES: "false"
SECURITY_ENABLELOGIN: "true" SECURITY_ENABLELOGIN: "true"
@ -332,7 +332,7 @@ Thymeleaf is a server-side Java HTML template engine. It is used in Stirling-PDF
### Thymeleaf overview ### Thymeleaf overview
In Stirling-PDF, Thymeleaf is used to create HTML templates that are rendered on the server side. These templates are located in the `stirling-pdf/src/main/resources/templates` directory. Thymeleaf templates use a combination of HTML and special Thymeleaf attributes to dynamically generate content. In Stirling-PDF, Thymeleaf is used to create HTML templates that are rendered on the server side. These templates are located in the `src/main/resources/templates` directory. Thymeleaf templates use a combination of HTML and special Thymeleaf attributes to dynamically generate content.
Some examples of this are: Some examples of this are:
@ -384,7 +384,7 @@ This would generate n entries of tr for each person in exampleData
### Adding a New Feature to the Backend (API) ### Adding a New Feature to the Backend (API)
1. **Create a New Controller:** 1. **Create a New Controller:**
- Create a new Java class in the `stirling-pdf/src/main/java/stirling/software/SPDF/controller/api` directory. - Create a new Java class in the `src/main/java/stirling/software/SPDF/controller/api` directory.
- Annotate the class with `@RestController` and `@RequestMapping` to define the API endpoint. - Annotate the class with `@RestController` and `@RequestMapping` to define the API endpoint.
- Ensure to add API documentation annotations like `@Tag(name = "General", description = "General APIs")` and `@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")`. - Ensure to add API documentation annotations like `@Tag(name = "General", description = "General APIs")` and `@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")`.
@ -411,7 +411,7 @@ This would generate n entries of tr for each person in exampleData
``` ```
2. **Define the Service Layer:** (Not required but often useful) 2. **Define the Service Layer:** (Not required but often useful)
- Create a new service class in the `stirling-pdf/src/main/java/stirling/software/SPDF/service` directory. - Create a new service class in the `src/main/java/stirling/software/SPDF/service` directory.
- Implement the business logic for the new feature. - Implement the business logic for the new feature.
```java ```java
@ -463,7 +463,7 @@ This would generate n entries of tr for each person in exampleData
### Adding a New Feature to the Frontend (UI) ### Adding a New Feature to the Frontend (UI)
1. **Create a New Thymeleaf Template:** 1. **Create a New Thymeleaf Template:**
- Create a new HTML file in the `stirling-pdf/src/main/resources/templates` directory. - Create a new HTML file in the `src/main/resources/templates` directory.
- Use Thymeleaf attributes to dynamically generate content. - Use Thymeleaf attributes to dynamically generate content.
- Use `extract-page.html` as a base example for the HTML template, which is useful to ensure importing of the general layout, navbar, and footer. - Use `extract-page.html` as a base example for the HTML template, which is useful to ensure importing of the general layout, navbar, and footer.
@ -507,7 +507,7 @@ This would generate n entries of tr for each person in exampleData
``` ```
2. **Create a New Controller for the UI:** 2. **Create a New Controller for the UI:**
- Create a new Java class in the `stirling-pdf/src/main/java/stirling/software/SPDF/controller/ui` directory. - Create a new Java class in the `src/main/java/stirling/software/SPDF/controller/ui` directory.
- Annotate the class with `@Controller` and `@RequestMapping` to define the UI endpoint. - Annotate the class with `@Controller` and `@RequestMapping` to define the UI endpoint.
```java ```java
@ -537,7 +537,7 @@ This would generate n entries of tr for each person in exampleData
3. **Update the Navigation Bar:** 3. **Update the Navigation Bar:**
- Add a link to the new feature page in the navigation bar. - Add a link to the new feature page in the navigation bar.
- Update the `stirling-pdf/src/main/resources/templates/fragments/navbar.html` file. - Update the `src/main/resources/templates/fragments/navbar.html` file.
```html ```html
<li class="nav-item"> <li class="nav-item">
@ -551,7 +551,7 @@ When adding a new feature or modifying existing ones in Stirling-PDF, you'll nee
### 1. Locate Existing Language Files ### 1. Locate Existing Language Files
Find the existing `messages.properties` files in the `stirling-pdf/src/main/resources` directory. You'll see files like: Find the existing `messages.properties` files in the `src/main/resources` directory. You'll see files like:
- `messages.properties` (default, usually English) - `messages.properties` (default, usually English)
- `messages_en_GB.properties` - `messages_en_GB.properties`

View File

@ -4,7 +4,7 @@ FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be02
# Copy necessary files # Copy necessary files
COPY scripts /scripts COPY scripts /scripts
COPY pipeline /pipeline COPY pipeline /pipeline
COPY stirling-pdf/src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/ COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
#COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/ #COPY src/main/resources/static/fonts/*.otf /usr/share/fonts/opentype/noto/
COPY build/libs/*.jar app.jar COPY build/libs/*.jar app.jar

View File

@ -26,7 +26,7 @@ FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be02
# Copy necessary files # Copy necessary files
COPY scripts /scripts COPY scripts /scripts
COPY pipeline /pipeline COPY pipeline /pipeline
COPY stirling-pdf/src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/ COPY src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/
COPY --from=build /app/build/libs/*.jar app.jar COPY --from=build /app/build/libs/*.jar app.jar
ARG VERSION_TAG ARG VERSION_TAG

View File

@ -10,7 +10,7 @@ Fork Stirling-PDF and create a new branch out of `main`.
Then add a reference to the language in the navbar by adding a new language entry to the dropdown: Then add a reference to the language in the navbar by adding a new language entry to the dropdown:
- Edit the file: [languages.html](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/stirling-pdf/src/main/resources/templates/fragments/languages.html) - Edit the file: [languages.html](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html)
For example, to add Polish, you would add: For example, to add Polish, you would add:
@ -25,7 +25,7 @@ The `data-bs-language-code` is the code used to reference the file in the next s
Start by copying the existing English property file: Start by copying the existing English property file:
- [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/stirling-pdf/src/main/resources/messages_en_GB.properties) - [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties)
Copy and rename it to `messages_{your data-bs-language-code here}.properties`. In the Polish example, you would set the name to `messages_pl_PL.properties`. Copy and rename it to `messages_{your data-bs-language-code here}.properties`. In the Polish example, you would set the name to `messages_pl_PL.properties`.

View File

@ -116,46 +116,46 @@ Stirling-PDF currently supports 40 languages!
| Language | Progress | | Language | Progress |
| -------------------------------------------- | -------------------------------------- | | -------------------------------------------- | -------------------------------------- |
| Arabic (العربية) (ar_AR) | ![71%](https://geps.dev/progress/71) | | Arabic (العربية) (ar_AR) | ![72%](https://geps.dev/progress/72) |
| Azerbaijani (Azərbaycan Dili) (az_AZ) | ![72%](https://geps.dev/progress/72) | | Azerbaijani (Azərbaycan Dili) (az_AZ) | ![72%](https://geps.dev/progress/72) |
| Basque (Euskara) (eu_ES) | ![42%](https://geps.dev/progress/42) | | Basque (Euskara) (eu_ES) | ![42%](https://geps.dev/progress/42) |
| Bulgarian (Български) (bg_BG) | ![79%](https://geps.dev/progress/79) | | Bulgarian (Български) (bg_BG) | ![80%](https://geps.dev/progress/80) |
| Catalan (Català) (ca_CA) | ![78%](https://geps.dev/progress/78) | | Catalan (Català) (ca_CA) | ![79%](https://geps.dev/progress/79) |
| Croatian (Hrvatski) (hr_HR) | ![70%](https://geps.dev/progress/70) | | Croatian (Hrvatski) (hr_HR) | ![71%](https://geps.dev/progress/71) |
| Czech (Česky) (cs_CZ) | ![81%](https://geps.dev/progress/81) | | Czech (Česky) (cs_CZ) | ![82%](https://geps.dev/progress/82) |
| Danish (Dansk) (da_DK) | ![71%](https://geps.dev/progress/71) | | Danish (Dansk) (da_DK) | ![72%](https://geps.dev/progress/72) |
| Dutch (Nederlands) (nl_NL) | ![69%](https://geps.dev/progress/69) | | Dutch (Nederlands) (nl_NL) | ![70%](https://geps.dev/progress/70) |
| English (English) (en_GB) | ![100%](https://geps.dev/progress/100) | | English (English) (en_GB) | ![100%](https://geps.dev/progress/100) |
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| French (Français) (fr_FR) | ![80%](https://geps.dev/progress/80) | | French (Français) (fr_FR) | ![81%](https://geps.dev/progress/81) |
| German (Deutsch) (de_DE) | ![97%](https://geps.dev/progress/97) | | German (Deutsch) (de_DE) | ![98%](https://geps.dev/progress/98) |
| Greek (Ελληνικά) (el_GR) | ![78%](https://geps.dev/progress/78) | | Greek (Ελληνικά) (el_GR) | ![79%](https://geps.dev/progress/79) |
| Hindi (हिंदी) (hi_IN) | ![78%](https://geps.dev/progress/78) | | Hindi (हिंदी) (hi_IN) | ![78%](https://geps.dev/progress/78) |
| Hungarian (Magyar) (hu_HU) | ![89%](https://geps.dev/progress/89) | | Hungarian (Magyar) (hu_HU) | ![86%](https://geps.dev/progress/86) |
| Indonesian (Bahasa Indonesia) (id_ID) | ![72%](https://geps.dev/progress/72) | | Indonesian (Bahasa Indonesia) (id_ID) | ![72%](https://geps.dev/progress/72) |
| Irish (Gaeilge) (ga_IE) | ![79%](https://geps.dev/progress/79) | | Irish (Gaeilge) (ga_IE) | ![80%](https://geps.dev/progress/80) |
| Italian (Italiano) (it_IT) | ![97%](https://geps.dev/progress/97) | | Italian (Italiano) (it_IT) | ![96%](https://geps.dev/progress/96) |
| Japanese (日本語) (ja_JP) | ![79%](https://geps.dev/progress/79) | | Japanese (日本語) (ja_JP) | ![80%](https://geps.dev/progress/80) |
| Korean (한국어) (ko_KR) | ![78%](https://geps.dev/progress/78) | | Korean (한국어) (ko_KR) | ![79%](https://geps.dev/progress/79) |
| Norwegian (Norsk) (no_NB) | ![76%](https://geps.dev/progress/76) | | Norwegian (Norsk) (no_NB) | ![77%](https://geps.dev/progress/77) |
| Persian (فارسی) (fa_IR) | ![74%](https://geps.dev/progress/74) | | Persian (فارسی) (fa_IR) | ![75%](https://geps.dev/progress/75) |
| Polish (Polski) (pl_PL) | ![83%](https://geps.dev/progress/83) | | Polish (Polski) (pl_PL) | ![84%](https://geps.dev/progress/84) |
| Portuguese (Português) (pt_PT) | ![79%](https://geps.dev/progress/79) | | Portuguese (Português) (pt_PT) | ![80%](https://geps.dev/progress/80) |
| Portuguese Brazilian (Português) (pt_BR) | ![84%](https://geps.dev/progress/84) | | Portuguese Brazilian (Português) (pt_BR) | ![85%](https://geps.dev/progress/85) |
| Romanian (Română) (ro_RO) | ![66%](https://geps.dev/progress/66) | | Romanian (Română) (ro_RO) | ![67%](https://geps.dev/progress/67) |
| Russian (Русский) (ru_RU) | ![84%](https://geps.dev/progress/84) | | Russian (Русский) (ru_RU) | ![85%](https://geps.dev/progress/85) |
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![51%](https://geps.dev/progress/51) | | Serbian Latin alphabet (Srpski) (sr_LATN_RS) | ![51%](https://geps.dev/progress/51) |
| Simplified Chinese (简体中文) (zh_CN) | ![84%](https://geps.dev/progress/84) | | Simplified Chinese (简体中文) (zh_CN) | ![85%](https://geps.dev/progress/85) |
| Slovakian (Slovensky) (sk_SK) | ![60%](https://geps.dev/progress/60) | | Slovakian (Slovensky) (sk_SK) | ![60%](https://geps.dev/progress/60) |
| Slovenian (Slovenščina) (sl_SI) | ![82%](https://geps.dev/progress/82) | | Slovenian (Slovenščina) (sl_SI) | ![83%](https://geps.dev/progress/83) |
| Spanish (Español) (es_ES) | ![86%](https://geps.dev/progress/86) | | Spanish (Español) (es_ES) | ![87%](https://geps.dev/progress/87) |
| Swedish (Svenska) (sv_SE) | ![76%](https://geps.dev/progress/76) | | Swedish (Svenska) (sv_SE) | ![76%](https://geps.dev/progress/76) |
| Thai (ไทย) (th_TH) | ![68%](https://geps.dev/progress/68) | | Thai (ไทย) (th_TH) | ![69%](https://geps.dev/progress/69) |
| Tibetan (བོད་ཡིག་) (bo_CN) | ![75%](https://geps.dev/progress/75) | | Tibetan (བོད་ཡིག་) (bo_CN) | ![76%](https://geps.dev/progress/76) |
| Traditional Chinese (繁體中文) (zh_TW) | ![85%](https://geps.dev/progress/85) | | Traditional Chinese (繁體中文) (zh_TW) | ![85%](https://geps.dev/progress/85) |
| Turkish (Türkçe) (tr_TR) | ![85%](https://geps.dev/progress/85) | | Turkish (Türkçe) (tr_TR) | ![86%](https://geps.dev/progress/86) |
| Ukrainian (Українська) (uk_UA) | ![84%](https://geps.dev/progress/84) | | Ukrainian (Українська) (uk_UA) | ![85%](https://geps.dev/progress/85) |
| Vietnamese (Tiếng Việt) (vi_VN) | ![66%](https://geps.dev/progress/66) | | Vietnamese (Tiếng Việt) (vi_VN) | ![67%](https://geps.dev/progress/67) |
| Malayalam (മലയാളം) (ml_IN) | ![85%](https://geps.dev/progress/85) | | Malayalam (മലയാളം) (ml_IN) | ![85%](https://geps.dev/progress/85) |
## Stirling PDF Enterprise ## Stirling PDF Enterprise

View File

@ -26,124 +26,21 @@ ext {
bouncycastleVersion = "1.80" bouncycastleVersion = "1.80"
springSecuritySamlVersion = "6.5.0" springSecuritySamlVersion = "6.5.0"
openSamlVersion = "4.3.2" openSamlVersion = "4.3.2"
commonmarkVersion = "0.24.0"
tempJrePath = null tempJrePath = null
} }
jar { group = "stirling.software"
enabled = false version = "0.46.2"
manifest {
attributes "Implementation-Title": "Stirling-PDF", java {
"Implementation-Version": project.version // 17 is lowest but we support and recommend 21
} sourceCompatibility = JavaVersion.VERSION_17
} }
bootJar { repositories {
enabled = false mavenCentral()
} maven { url = "https://build.shibboleth.net/maven/releases" }
maven { url = "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
sourceSets {
main {
java {
if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false' || System.getenv('DISABLE_ADDITIONAL_FEATURES') == 'true'
|| (project.hasProperty('DISABLE_ADDITIONAL_FEATURES')
&& System.getProperty('DISABLE_ADDITIONAL_FEATURES') == 'true')) {
exclude 'stirling/software/proprietary/security/**'
}
if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
exclude 'stirling/software/SPDF/UI/impl/**'
}
}
}
test {
java {
if (System.getenv('DOCKER_ENABLE_SECURITY') == 'false' || System.getenv('DISABLE_ADDITIONAL_FEATURES') == 'true'
|| (project.hasProperty('DISABLE_ADDITIONAL_FEATURES')
&& System.getProperty('DISABLE_ADDITIONAL_FEATURES') == 'true')) {
exclude 'stirling/software/proprietary/security/**'
}
if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
exclude 'stirling/software/SPDF/UI/impl/**'
}
}
}
}
allprojects {
group = 'stirling.software'
version = '0.46.2'
configurations.configureEach {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"
}
}
subprojects {
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'com.diffplug.spotless'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
java {
// 17 is lowest but we support and recommend 21
sourceCompatibility = JavaVersion.VERSION_17
}
bootJar {
enabled = false
}
repositories {
mavenCentral()
}
configurations.configureEach {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
// Exclude vulnerable BouncyCastle version used in tableau
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
exclude group: 'org.bouncycastle', module: 'bcutil-jdk15on'
exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on'
}
dependencyManagement {
imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:$springBootVersion"
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
//tmp for security bumps
implementation 'ch.qos.logback:logback-core:1.5.18'
implementation 'ch.qos.logback:logback-classic:1.5.18'
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'
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
dependsOn "spotlessApply"
}
compileJava {
options.compilerArgs << "-parameters"
}
test {
useJUnitPlatform()
}
} }
licenseReport { licenseReport {
@ -202,9 +99,10 @@ jpackage {
mainJar = "Stirling-PDF-${project.version}.jar" mainJar = "Stirling-PDF-${project.version}.jar"
appName = "Stirling PDF" appName = "Stirling PDF"
appVersion = project.version appVersion = project.version
// appVersion = "2005.45.1"
vendor = "Stirling PDF Inc" vendor = "Stirling PDF Inc"
appDescription = "Stirling PDF - Your Local PDF Editor" appDescription = "Stirling PDF - Your Local PDF Editor"
icon = "stirling-pdf/src/main/resources/static/favicon.ico" icon = "src/main/resources/static/favicon.ico"
verbose = true verbose = true
// mainClass = "org.springframework.boot.loader.launch.JarLauncher" // mainClass = "org.springframework.boot.loader.launch.JarLauncher"
@ -243,10 +141,10 @@ jpackage {
installDir = "C:/Program Files/Stirling-PDF" installDir = "C:/Program Files/Stirling-PDF"
} }
// MacOS-specific configuration // macOS-specific configuration
mac { mac {
appVersion = getMacVersion(project.version.toString()) appVersion = getMacVersion(project.version.toString())
icon = "stirling-pdf/src/main/resources/static/favicon.icns" icon = "src/main/resources/static/favicon.icns"
type = "dmg" type = "dmg"
macPackageIdentifier = "Stirling PDF" macPackageIdentifier = "Stirling PDF"
macPackageName = "Stirling PDF" macPackageName = "Stirling PDF"
@ -268,7 +166,7 @@ jpackage {
// Linux-specific configuration // Linux-specific configuration
linux { linux {
appVersion = project.version appVersion = project.version
icon = "stirling-pdf/src/main/resources/static/favicon.png" icon = "src/main/resources/static/favicon.png"
type = "deb" // Can also use "rpm" for Red Hat-based systems type = "deb" // Can also use "rpm" for Red Hat-based systems
// Debian package configuration // Debian package configuration
@ -304,15 +202,10 @@ jpackage {
]*/ ]*/
// Add copyright and license information // Add copyright and license information
copyright = "Copyright © 2025 Stirling PDF Inc." copyright = "Copyright © 2024 Stirling Software"
licenseFile = "LICENSE" licenseFile = "LICENSE"
} }
//tasks.wrapper {
// gradleVersion = "8.14"
// distributionType = Wrapper.DistributionType.ALL
//}
tasks.register('jpackageMacX64') { tasks.register('jpackageMacX64') {
group = 'distribution' group = 'distribution'
description = 'Packages app for MacOS x86_64' description = 'Packages app for MacOS x86_64'
@ -345,7 +238,7 @@ tasks.register('jpackageMacX64') {
'--main-class', 'org.springframework.boot.loader.launch.JarLauncher', '--main-class', 'org.springframework.boot.loader.launch.JarLauncher',
'--runtime-image', file(jrePath + "/zulu-17.jre/Contents/Home"), '--runtime-image', file(jrePath + "/zulu-17.jre/Contents/Home"),
'--dest', 'build/jpackage/x86_64', '--dest', 'build/jpackage/x86_64',
'--icon', 'stirling-pdf/src/main/resources/static/favicon.icns', '--icon', 'src/main/resources/static/favicon.icns',
'--app-version', getMacVersion(project.version.toString()), '--app-version', getMacVersion(project.version.toString()),
'--mac-package-name', 'Stirling PDF (x86_64)', '--mac-package-name', 'Stirling PDF (x86_64)',
'--mac-package-identifier', 'Stirling PDF (x86_64)', '--mac-package-identifier', 'Stirling PDF (x86_64)',
@ -394,12 +287,12 @@ tasks.register('downloadTempJre') {
def jreArchive = new File(tmpDir, 'jre.tar.gz') def jreArchive = new File(tmpDir, 'jre.tar.gz')
def jreDir = new File(tmpDir, 'jre') def jreDir = new File(tmpDir, 'jre')
println "Downloading JRE to $jreArchive" println "Downloading JRE to $jreArchive..."
jreArchive.withOutputStream { out -> jreArchive.withOutputStream { out ->
new URI(jreUrl).toURL().withInputStream { from -> out << from } new URI(jreUrl).toURL().withInputStream { from -> out << from }
} }
println "Extracting JRE to $jreDir" println "Extracting JRE to $jreDir..."
jreDir.mkdirs() jreDir.mkdirs()
providers.exec { providers.exec {
commandLine 'tar', '-xzf', jreArchive.absolutePath, '-C', jreDir.absolutePath, '--strip-components=1' commandLine 'tar', '-xzf', jreArchive.absolutePath, '-C', jreDir.absolutePath, '--strip-components=1'
@ -431,7 +324,7 @@ tasks.register('cleanTempJre') {
} }
launch4j { launch4j {
icon = "${projectDir}/stirling-pdf/src/main/resources/static/favicon.ico" icon = "${projectDir}/src/main/resources/static/favicon.ico"
outfile="Stirling-PDF.exe" outfile="Stirling-PDF.exe"
@ -442,7 +335,7 @@ launch4j {
} }
jarTask = tasks.bootJar jarTask = tasks.bootJar
errTitle="Encountered error, do you have Java 21?" errTitle="Encountered error, Do you have Java 21?"
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe" downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') { if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
@ -484,12 +377,159 @@ sonar {
property "sonar.projectKey", "Stirling-Tools_Stirling-PDF" property "sonar.projectKey", "Stirling-Tools_Stirling-PDF"
property "sonar.organization", "stirling-tools" property "sonar.organization", "stirling-tools"
property "sonar.exclusions", "**/build-wrapper-dump.json, **/src/main/java/org/apache/**, **/src/main/resources/static/pdfjs/**, **/src/main/resources/static/pdfjs-legacy/**, **/src/main/resources/static/js/thirdParty/**" property "sonar.exclusions", "**/build-wrapper-dump.json, src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
property "sonar.coverage.exclusions", "**/src/main/java/org/apache/**, **/src/main/resources/static/pdfjs/**, **/src/main/resources/static/pdfjs-legacy/**, **/src/main/resources/static/js/thirdParty/**" property "sonar.coverage.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
property "sonar.cpd.exclusions", "**/src/main/java/org/apache/**, **/src/main/resources/static/pdfjs/**, **/src/main/resources/static/pdfjs-legacy/**, **/src/main/resources/static/js/thirdParty/**" property "sonar.cpd.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
} }
} }
//gradleLint {
// rules=['unused-dependency']
// }
tasks.wrapper {
gradleVersion = "8.14"
distributionType = Wrapper.DistributionType.ALL
}
//tasks.withType(JavaCompile) {
// options.compilerArgs << "-Xlint:deprecation"
//}
configurations.all {
// Remove all commons-logging dependencies so that only spring-jcl is used
exclude group: 'commons-logging', module: 'commons-logging'
// 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'
exclude group: 'org.bouncycastle', module: 'bcutil-jdk15on'
exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on'
}
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
implementation "me.friwi:jcefmaven:135.0.20"
implementation "org.openjfx:javafx-controls:21"
implementation "org.openjfx:javafx-swing:21"
}
//security updates
implementation "org.springframework:spring-webmvc:6.2.7"
implementation("io.github.pixee:java-security-toolkit:1.2.1")
// Exclude Tomcat and include Jetty
// implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
// implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
implementation 'com.posthog.java:posthog:1.2.0'
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false" || System.getenv('DISABLE_ADDITIONAL_FEATURES') != 'true'
|| (project.hasProperty('DISABLE_ADDITIONAL_FEATURES')
&& System.getProperty('DISABLE_ADDITIONAL_FEATURES') != 'true')) {
implementation project(':proprietary')
}
// Batik
implementation "org.apache.xmlgraphics:batik-all:1.19"
// TwelveMonkeys
runtimeOnly "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-psd:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
// Image metadata extractor
implementation "com.drewnoakes:metadata-extractor:2.19.0"
implementation "commons-io:commons-io:2.19.0"
// implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8"
// General PDF
// https://mvnrepository.com/artifact/com.opencsv/opencsv
implementation ("com.opencsv:opencsv:5.11")
// implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion")
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion")
// https://mvnrepository.com/artifact/technology.tabula/tabula
implementation ('technology.tabula:tabula:1.0.5') {
exclude group: "org.slf4j", module: "slf4j-simple"
exclude group: "org.bouncycastle", module: "bcprov-jdk15on"
exclude group: "com.google.code.gson", module: "gson"
exclude group: "commons-io", module: "commons-io"
}
implementation 'org.apache.pdfbox:jbig2-imageio:3.0.4'
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
implementation "io.micrometer:micrometer-core:1.15.0"
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
// https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation "org.commonmark:commonmark:0.24.0"
implementation "org.commonmark:commonmark-ext-gfm-tables:0.24.0"
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0"
implementation "com.fathzer:javaluator:3.0.6"
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
// Mockito (core)
testImplementation 'org.mockito:mockito-core:5.18.0'
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
dependsOn "spotlessApply"
}
compileJava {
options.compilerArgs << "-parameters"
}
task writeVersion {
def propsFile = file("$projectDir/src/main/resources/version.properties")
def propsDir = propsFile.parentFile
doLast {
if (!propsDir.exists()) {
propsDir.mkdirs()
}
def props = new Properties()
props.setProperty("version", version)
props.store(propsFile.newWriter(), null)
}
}
processResources.dependsOn(writeVersion)
swaggerhubUpload { swaggerhubUpload {
// dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs // dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs
api = "Stirling-PDF" // The name of your API on SwaggerHub api = "Stirling-PDF" // The name of your API on SwaggerHub
@ -500,43 +540,25 @@ swaggerhubUpload {
oas = "3.0.0" // The version of the OpenAPI Specification you"re using oas = "3.0.0" // The version of the OpenAPI Specification you"re using
} }
jar {
enabled = false
manifest {
attributes "Implementation-Title": "Stirling-PDF",
"Implementation-Version": project.version
}
}
tasks.named("test") { tasks.named("test") {
useJUnitPlatform() useJUnitPlatform()
} }
tasks.register('writeVersion') { task printVersion {
def propsFile = file("$projectDir/stirling-pdf/src/main/resources/version.properties")
def propsDir = propsFile.parentFile
doLast {
if (propsDir.exists()) {
if (propsFile.exists()) {
println "File exists: $propsFile"
} else {
println "$propsFile does not exist. Creating file."
propsFile.createNewFile()
}
} else {
println "Creating directory: $propsDir"
propsDir.mkdirs()
propsFile.createNewFile()
}
def props = new Properties()
props.setProperty("version", version)
props.store(propsFile.newWriter(), null)
}
}
processResources.dependsOn(writeVersion)
tasks.register('printVersion') {
doLast { doLast {
println project.version println project.version
} }
} }
tasks.register('printMacVersion') { task printMacVersion {
doLast { doLast {
println getMacVersion(project.version.toString()) println getMacVersion(project.version.toString())
} }

2
common/.gitignore vendored
View File

@ -124,7 +124,6 @@ SwaggerDoc.json
*.rar *.rar
*.db *.db
/build /build
/common/build/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
@ -194,3 +193,4 @@ id_ed25519.pub
# node_modules # node_modules
node_modules/ node_modules/
*.mjs

View File

@ -1,9 +1,41 @@
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.5.0'
}
}
dependencies { dependencies {
api 'org.springframework.boot:spring-boot-starter-web' api 'org.springframework.boot:spring-boot-starter-web'
api 'org.springframework.boot:spring-boot-starter-thymeleaf' api 'org.springframework.boot:spring-boot-starter-thymeleaf'
api 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1' api 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
api 'com.fathzer:javaluator:3.0.6' api 'com.fathzer:javaluator:3.0.6'
api 'com.posthog.java:posthog:1.2.0' api 'com.posthog.java:posthog:1.2.0'
api 'io.github.pixee:java-security-toolkit:1.2.1'
api 'org.apache.commons:commons-lang3:3.17.0' api 'org.apache.commons:commons-lang3:3.17.0'
api 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor api 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor
api 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8' api 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
@ -11,5 +43,10 @@ dependencies {
api 'jakarta.servlet:jakarta.servlet-api:6.1.0' api 'jakarta.servlet:jakarta.servlet-api:6.1.0'
api 'org.snakeyaml:snakeyaml-engine:2.9' api 'org.snakeyaml:snakeyaml-engine:2.9'
api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8" api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8"
api 'jakarta.mail:jakarta.mail-api:2.1.3'
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,7 +1,5 @@
package stirling.software.common.configuration; package stirling.software.common.configuration;
import io.github.pixee.security.SystemCommand;
import jakarta.annotation.PostConstruct;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -151,12 +149,12 @@ public class AppConfig {
@Bean(name = "activeSecurity") @Bean(name = "activeSecurity")
public boolean activeSecurity() { public boolean activeSecurity() {
String disableAdditionalFeatures = env.getProperty("DISABLE_ADDITIONAL_FEATURES"); String additionalFeaturesOff = env.getProperty("DISABLE_ADDITIONAL_FEATURES");
if (disableAdditionalFeatures != null) { if (additionalFeaturesOff != null) {
// DISABLE_ADDITIONAL_FEATURES=true means security OFF, so return false // DISABLE_ADDITIONAL_FEATURES=true means security OFF, so return false
// DISABLE_ADDITIONAL_FEATURES=false means security ON, so return true // DISABLE_ADDITIONAL_FEATURES=false means security ON, so return true
return !Boolean.parseBoolean(disableAdditionalFeatures); return !Boolean.parseBoolean(additionalFeaturesOff);
} }
return env.getProperty("DOCKER_ENABLE_SECURITY", Boolean.class, true); return env.getProperty("DOCKER_ENABLE_SECURITY", Boolean.class, true);
@ -166,7 +164,7 @@ public class AppConfig {
@ConditionalOnMissingClass( @ConditionalOnMissingClass(
"stirling.software.proprietary.security.configuration.SecurityConfiguration") "stirling.software.proprietary.security.configuration.SecurityConfiguration")
public boolean missingActiveSecurity() { public boolean missingActiveSecurity() {
return true; return false;
} }
@Bean(name = "directoryFilter") @Bean(name = "directoryFilter")

View File

@ -344,10 +344,10 @@ public class ApplicationProperties {
@Override @Override
public String toString() { public String toString() {
return """ return """
Driver { Driver {
driverName='%s' driverName='%s'
} }
""" """
.formatted(driverName); .formatted(driverName);
} }
} }

View File

@ -1,39 +0,0 @@
package stirling.software.common.model.api.converters;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import stirling.software.common.model.api.PDFFile;
@Data
@EqualsAndHashCode(callSuper = true)
public class EmlToPdfRequest extends PDFFile {
// fileInput is inherited from PDFFile
@Schema(
description = "Include email attachments in the PDF output",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
example = "false")
private boolean includeAttachments = false;
@Schema(
description = "Maximum attachment size in MB to include (default 10MB, range: 1-100)",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
example = "10",
minimum = "1",
maximum = "100")
private int maxAttachmentSizeMB = 10;
@Schema(
description = "Download HTML intermediate file instead of PDF",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
example = "false")
private boolean downloadHtml = false;
@Schema(
description = "Include CC and BCC recipients in header (if available)",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
example = "true")
private boolean includeAllRecipients = true;
}

View File

@ -208,7 +208,7 @@ public class PostHogService {
// New environment variables // New environment variables
dockerMetrics.put("version_tag", System.getenv("VERSION_TAG")); dockerMetrics.put("version_tag", System.getenv("VERSION_TAG"));
dockerMetrics.put("additional_features_off", System.getenv("ADDITIONAL_FEATURES_OFF")); dockerMetrics.put("without_enhanced_features", System.getenv("WITHOUT_ENHANCED_FEATURES"));
dockerMetrics.put("fat_docker", System.getenv("FAT_DOCKER")); dockerMetrics.put("fat_docker", System.getenv("FAT_DOCKER"));
return dockerMetrics; return dockerMetrics;

View File

@ -1,14 +0,0 @@
package stirling.software.common.util;
import java.util.Collection;
public class ValidationUtil {
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,5 @@
package stirling.software.common.util; package stirling.software.common.util;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
@ -19,6 +10,18 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
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;
class CheckProgramInstallTest { class CheckProgramInstallTest {
private MockedStatic<ProcessExecutor> mockProcessExecutor; private MockedStatic<ProcessExecutor> mockProcessExecutor;

View File

@ -19,6 +19,7 @@ import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.configuration.RuntimePathConfig; import stirling.software.common.configuration.RuntimePathConfig;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)

View File

@ -1,7 +1,10 @@
package stirling.software.common.util; package stirling.software.common.util;
import static org.mockito.Mockito.*;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -9,13 +12,11 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.model.enumeration.UsernameAttribute; import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.common.model.oauth2.GitHubProvider; import stirling.software.common.model.oauth2.GitHubProvider;
import stirling.software.common.model.oauth2.GoogleProvider; import stirling.software.common.model.oauth2.GoogleProvider;
import stirling.software.common.model.oauth2.Provider; import stirling.software.common.model.oauth2.Provider;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class ProviderUtilsTest { class ProviderUtilsTest {
@ -28,19 +29,19 @@ class ProviderUtilsTest {
when(provider.getClientSecret()).thenReturn("clientSecret"); when(provider.getClientSecret()).thenReturn("clientSecret");
when(provider.getScopes()).thenReturn(List.of("read:user")); when(provider.getScopes()).thenReturn(List.of("read:user"));
assertTrue(ProviderUtils.validateProvider(provider)); Assertions.assertTrue(ProviderUtils.validateProvider(provider));
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("providerParams") @MethodSource("providerParams")
void testUnsuccessfulValidation(Provider provider) { void testUnsuccessfulValidation(Provider provider) {
assertFalse(ProviderUtils.validateProvider(provider)); Assertions.assertFalse(ProviderUtils.validateProvider(provider));
} }
public static Stream<Arguments> providerParams() { public static Stream<Arguments> providerParams() {
Provider generic = null; Provider generic = null;
var google = var google =
new GoogleProvider(null, "clientSecret", List.of("scope"), UsernameAttribute.EMAIL); new GoogleProvider(null, "clientSecret", List.of("scope"), UsernameAttribute.EMAIL);
var github = new GitHubProvider("clientId", "", List.of("scope"), UsernameAttribute.LOGIN); var github = new GitHubProvider("clientId", "", List.of("scope"), UsernameAttribute.LOGIN);
return Stream.of(Arguments.of(generic), Arguments.of(google), Arguments.of(github)); return Stream.of(Arguments.of(generic), Arguments.of(google), Arguments.of(github));

View File

@ -1,11 +1,13 @@
package stirling.software.common.util.misc; package stirling.software.common.util.misc;
import org.junit.jupiter.api.Test;
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.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
import stirling.software.common.model.api.misc.HighContrastColorCombination;
import stirling.software.common.model.api.misc.ReplaceAndInvert;
class HighContrastColorReplaceDeciderTest { class HighContrastColorReplaceDeciderTest {
@Test @Test

View File

@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import stirling.software.common.model.api.misc.ReplaceAndInvert; import stirling.software.common.model.api.misc.ReplaceAndInvert;
class InvertFullColorStrategyTest { class InvertFullColorStrategyTest {

View File

@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import stirling.software.common.model.api.misc.ReplaceAndInvert; import stirling.software.common.model.api.misc.ReplaceAndInvert;
class ReplaceAndInvertColorStrategyTest { class ReplaceAndInvertColorStrategyTest {

View File

@ -1,14 +1,17 @@
package stirling.software.common.util.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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; 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.common.model.api.security.RedactionArea;
class StringToArrayListPropertyEditorTest { class StringToArrayListPropertyEditorTest {
private StringToArrayListPropertyEditor editor; private StringToArrayListPropertyEditor editor;

View File

@ -14,9 +14,9 @@ services:
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DISABLE_ADDITIONAL_FEATURES: "false" DISABLE_ADDITIONAL_FEATURES: "false"
SECURITY_ENABLELOGIN: "true" SECURITY_ENABLELOGIN: "true"

View File

@ -14,9 +14,9 @@ services:
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DISABLE_ADDITIONAL_FEATURES: "false" DISABLE_ADDITIONAL_FEATURES: "false"
SECURITY_ENABLELOGIN: "true" SECURITY_ENABLELOGIN: "true"

View File

@ -14,8 +14,8 @@ services:
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DISABLE_ADDITIONAL_FEATURES: "true" DISABLE_ADDITIONAL_FEATURES: "true"
SECURITY_ENABLELOGIN: "false" SECURITY_ENABLELOGIN: "false"

View File

@ -14,9 +14,9 @@ services:
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DISABLE_ADDITIONAL_FEATURES: "true" DISABLE_ADDITIONAL_FEATURES: "true"
SECURITY_ENABLELOGIN: "false" SECURITY_ENABLELOGIN: "false"

View File

@ -14,9 +14,9 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
volumes: volumes:
- ./stirling/latest/data:/usr/share/tessdata:rw - /stirling/latest/data:/usr/share/tessdata:rw
- ./stirling/latest/config:/configs:rw - /stirling/latest/config:/configs:rw
- ./stirling/latest/logs:/logs:rw - /stirling/latest/logs:/logs:rw
environment: environment:
DISABLE_ADDITIONAL_FEATURES: "false" DISABLE_ADDITIONAL_FEATURES: "false"
SECURITY_ENABLELOGIN: "true" SECURITY_ENABLELOGIN: "true"

View File

@ -124,7 +124,6 @@ SwaggerDoc.json
*.rar *.rar
*.db *.db
/build /build
/proprietary/build/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
@ -194,3 +193,4 @@ id_ed25519.pub
# node_modules # node_modules
node_modules/ node_modules/
*.mjs

View File

@ -1,7 +1,28 @@
plugins {
id 'java-library'
id 'io.spring.dependency-management' version '1.1.7'
}
repositories { repositories {
mavenCentral()
maven { url = "https://build.shibboleth.net/maven/releases" } maven { url = "https://build.shibboleth.net/maven/releases" }
} }
java {
sourceCompatibility = JavaVersion.VERSION_17
}
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.5.0'
}
}
dependencies { dependencies {
implementation project(':common') implementation project(':common')
@ -21,6 +42,7 @@ dependencies {
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17 // https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
implementation 'org.bouncycastle:bcprov-jdk18on:1.80' implementation 'org.bouncycastle:bcprov-jdk18on:1.80'
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE' implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE'
api 'io.micrometer:micrometer-registry-prometheus' api 'io.micrometer:micrometer-registry-prometheus'
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5' implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
@ -32,6 +54,14 @@ dependencies {
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion" implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
} }
implementation 'com.coveo:saml-client:5.0.0' implementation 'com.coveo:saml-client:5.0.0'
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.mockito:mockito-inline:5.2.0'
} }
tasks.register('prepareKotlinBuildScriptModel') {} tasks.register('prepareKotlinBuildScriptModel') {}

View File

@ -38,7 +38,6 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
public static final String LOGOUT_PATH = "/login?logout=true"; public static final String LOGOUT_PATH = "/login?logout=true";
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final AppConfig appConfig; private final AppConfig appConfig;
@Override @Override

View File

@ -6,7 +6,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
@ -56,7 +55,6 @@ import stirling.software.proprietary.security.session.SessionPersistentRegistry;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableMethodSecurity @EnableMethodSecurity
@DependsOn("runningProOrHigher")
public class SecurityConfiguration { public class SecurityConfiguration {
private final CustomUserDetailsService userDetailsService; private final CustomUserDetailsService userDetailsService;

View File

@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.UUID; import java.util.UUID;
import org.opensaml.saml.saml2.core.AuthnRequest; import org.opensaml.saml.saml2.core.AuthnRequest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -29,8 +30,8 @@ import stirling.software.common.model.ApplicationProperties.Security.SAML2;
@Configuration @Configuration
@Slf4j @Slf4j
@ConditionalOnProperty(value = "security.saml2.enabled", havingValue = "true")
@RequiredArgsConstructor @RequiredArgsConstructor
@ConditionalOnBooleanProperty("security.saml2.enabled")
public class SAML2Configuration { public class SAML2Configuration {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;

View File

@ -1,5 +1,5 @@
echo "Running Stirling PDF with DISABLE_ADDITIONAL_FEATURES=${DISABLE_ADDITIONAL_FEATURES} and VERSION_TAG=${VERSION_TAG}" echo "Running Stirling PDF with DISABLE_ADDITIONAL_FEATURES=${DISABLE_ADDITIONAL_FEATURES} and VERSION_TAG=${VERSION_TAG}"
# Check for DISABLE_ADDITIONAL_FEATURES and download the appropriate JAR if required # Check for $DISABLE_ADDITIONAL_FEATURES and download the appropriate JAR if required
if [ "$DISABLE_ADDITIONAL_FEATURES" = "false" ] && [ "$VERSION_TAG" != "alpha" ]; then if [ "$DISABLE_ADDITIONAL_FEATURES" = "false" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ ! -f app-security.jar ]; then if [ ! -f app-security.jar ]; then
echo "Trying to download from: https://files.stirlingpdf.com/v$VERSION_TAG/Stirling-PDF-with-login.jar" echo "Trying to download from: https://files.stirlingpdf.com/v$VERSION_TAG/Stirling-PDF-with-login.jar"

View File

@ -4,4 +4,4 @@ plugins {
} }
rootProject.name = 'Stirling-PDF' rootProject.name = 'Stirling-PDF'
include 'stirling-pdf', 'common', 'proprietary' include 'common', 'proprietary'

View File

@ -1,13 +1,13 @@
package stirling.software.proprietary.security.configuration.ee; package stirling.software.SPDF.EE;
import static stirling.software.proprietary.security.configuration.ee.KeygenLicenseVerifier.License;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.EnterpriseEdition; import stirling.software.common.model.ApplicationProperties.EnterpriseEdition;
import stirling.software.common.model.ApplicationProperties.Premium; import stirling.software.common.model.ApplicationProperties.Premium;
@ -15,6 +15,7 @@ import stirling.software.common.model.ApplicationProperties.Premium.ProFeatures.
@Configuration @Configuration
@Order(Ordered.HIGHEST_PRECEDENCE) @Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class EEAppConfig { public class EEAppConfig {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
@ -29,7 +30,6 @@ public class EEAppConfig {
} }
@Bean(name = "runningProOrHigher") @Bean(name = "runningProOrHigher")
@Qualifier("runningProOrHigher")
public boolean runningProOrHigher() { public boolean runningProOrHigher() {
return licenseKeyChecker.getPremiumLicenseEnabledResult() != License.NORMAL; return licenseKeyChecker.getPremiumLicenseEnabledResult() != License.NORMAL;
} }

View File

@ -1,4 +1,4 @@
package stirling.software.proprietary.security.configuration.ee; package stirling.software.SPDF.EE;
import java.net.URI; import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
@ -27,7 +27,7 @@ import stirling.software.common.util.GeneralUtils;
@RequiredArgsConstructor @RequiredArgsConstructor
public class KeygenLicenseVerifier { public class KeygenLicenseVerifier {
public enum License { enum License {
NORMAL, NORMAL,
PRO, PRO,
ENTERPRISE ENTERPRISE

View File

@ -1,4 +1,4 @@
package stirling.software.proprietary.security.configuration.ee; package stirling.software.SPDF.EE;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -10,12 +10,12 @@ import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.util.GeneralUtils; import stirling.software.common.util.GeneralUtils;
import stirling.software.proprietary.security.configuration.ee.KeygenLicenseVerifier.License;
@Slf4j
@Component @Component
@Slf4j
public class LicenseKeyChecker { public class LicenseKeyChecker {
private static final String FILE_PREFIX = "file:"; private static final String FILE_PREFIX = "file:";

View File

@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@ -26,7 +27,6 @@ import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.UI.WebBrowser; import stirling.software.SPDF.UI.WebBrowser;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.configuration.ConfigInitializer; import stirling.software.common.configuration.ConfigInitializer;
import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
@ -36,9 +36,9 @@ import stirling.software.common.util.UrlUtils;
@EnableScheduling @EnableScheduling
@SpringBootApplication( @SpringBootApplication(
scanBasePackages = { scanBasePackages = {
"stirling.software.SPDF",
"stirling.software.common", "stirling.software.common",
"stirling.software.proprietary" "stirling.software.SPDF",
"stirling.software.proprietary.security"
}, },
exclude = { exclude = {
DataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class,
@ -50,17 +50,20 @@ public class SPDFApplication {
private static String baseUrlStatic; private static String baseUrlStatic;
private static String contextPathStatic; private static String contextPathStatic;
private final AppConfig appConfig;
private final Environment env; private final Environment env;
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final WebBrowser webBrowser; private final WebBrowser webBrowser;
@Value("${baseUrl:http://localhost}")
private String baseUrl;
@Value("${server.servlet.context-path:/}")
private String contextPath;
public SPDFApplication( public SPDFApplication(
AppConfig appConfig,
Environment env, Environment env,
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Autowired(required = false) WebBrowser webBrowser) { @Autowired(required = false) WebBrowser webBrowser) {
this.appConfig = appConfig;
this.env = env; this.env = env;
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.webBrowser = webBrowser; this.webBrowser = webBrowser;
@ -149,14 +152,9 @@ public class SPDFApplication {
@PostConstruct @PostConstruct
public void init() { public void init() {
String baseUrl = appConfig.getBaseUrl(); baseUrlStatic = this.baseUrl;
String contextPath = appConfig.getContextPath(); contextPathStatic = this.contextPath;
String serverPort = appConfig.getServerPort();
baseUrlStatic = baseUrl;
contextPathStatic = contextPath;
serverPortStatic = serverPort;
String url = baseUrl + ":" + getStaticPort() + contextPath; String url = baseUrl + ":" + getStaticPort() + contextPath;
if (webBrowser != null if (webBrowser != null
&& Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) { && Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
webBrowser.initWebUI(url); webBrowser.initWebUI(url);
@ -167,7 +165,6 @@ public class SPDFApplication {
try { try {
String os = System.getProperty("os.name").toLowerCase(); String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime(); Runtime rt = Runtime.getRuntime();
if (os.contains("win")) { if (os.contains("win")) {
// For Windows // For Windows
SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url); SystemCommand.runCommand(rt, "rundll32 url.dll,FileProtocolHandler " + url);
@ -184,6 +181,17 @@ public class SPDFApplication {
log.info("Running configs {}", applicationProperties.toString()); log.info("Running configs {}", applicationProperties.toString());
} }
@Value("${server.port:8080}")
public void setServerPort(String port) {
if ("auto".equalsIgnoreCase(port)) {
// Use Spring Boot's automatic port assignment (server.port=0)
SPDFApplication.serverPortStatic =
"0"; // This will let Spring Boot assign an available port
} else {
SPDFApplication.serverPortStatic = port;
}
}
public static void setServerPortStatic(String port) { public static void setServerPortStatic(String port) {
if ("auto".equalsIgnoreCase(port)) { if ("auto".equalsIgnoreCase(port)) {
// Use Spring Boot's automatic port assignment (server.port=0) // Use Spring Boot's automatic port assignment (server.port=0)

View File

@ -14,21 +14,21 @@ import jakarta.servlet.http.HttpServletResponse;
public class CleanUrlInterceptor implements HandlerInterceptor { public class CleanUrlInterceptor implements HandlerInterceptor {
private static final List<String> ALLOWED_PARAMS = private static final List<String> ALLOWED_PARAMS =
Arrays.asList( Arrays.asList(
"lang", "lang",
"endpoint", "endpoint",
"endpoints", "endpoints",
"logout", "logout",
"error", "error",
"errorOAuth", "errorOAuth",
"file", "file",
"messageType", "messageType",
"infoMessage"); "infoMessage");
@Override @Override
public boolean preHandle( public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { throws Exception {
String queryString = request.getQueryString(); String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) { if (queryString != null && !queryString.isEmpty()) {
String requestURI = request.getRequestURI(); String requestURI = request.getRequestURI();
@ -69,15 +69,15 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
@Override @Override
public void postHandle( public void postHandle(
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
Object handler, Object handler,
ModelAndView modelAndView) {} ModelAndView modelAndView) {}
@Override @Override
public void afterCompletion( public void afterCompletion(
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
Object handler, Object handler,
Exception ex) {} Exception ex) {}
} }

View File

@ -39,14 +39,14 @@ public class EndpointInspector implements ApplicationListener<ContextRefreshedEv
private void discoverEndpoints() { private void discoverEndpoints() {
try { try {
Map<String, RequestMappingHandlerMapping> mappings = Map<String, RequestMappingHandlerMapping> mappings =
applicationContext.getBeansOfType(RequestMappingHandlerMapping.class); applicationContext.getBeansOfType(RequestMappingHandlerMapping.class);
for (Map.Entry<String, RequestMappingHandlerMapping> entry : mappings.entrySet()) { for (Map.Entry<String, RequestMappingHandlerMapping> entry : mappings.entrySet()) {
RequestMappingHandlerMapping mapping = entry.getValue(); RequestMappingHandlerMapping mapping = entry.getValue();
Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods(); Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> handlerEntry : for (Map.Entry<RequestMappingInfo, HandlerMethod> handlerEntry :
handlerMethods.entrySet()) { handlerMethods.entrySet()) {
RequestMappingInfo mappingInfo = handlerEntry.getKey(); RequestMappingInfo mappingInfo = handlerEntry.getKey();
HandlerMethod handlerMethod = handlerEntry.getValue(); HandlerMethod handlerMethod = handlerEntry.getValue();
@ -105,7 +105,7 @@ public class EndpointInspector implements ApplicationListener<ContextRefreshedEv
String infoString = mappingInfo.toString(); String infoString = mappingInfo.toString();
if (infoString.contains("{")) { if (infoString.contains("{")) {
String patternsSection = String patternsSection =
infoString.substring(infoString.indexOf("{") + 1, infoString.indexOf("}")); infoString.substring(infoString.indexOf("{") + 1, infoString.indexOf("}"));
for (String pattern : patternsSection.split(",")) { for (String pattern : patternsSection.split(",")) {
pattern = pattern.trim(); pattern = pattern.trim();

View File

@ -18,8 +18,8 @@ public class EndpointInterceptor implements HandlerInterceptor {
@Override @Override
public boolean preHandle( public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { throws Exception {
String requestURI = request.getRequestURI(); String requestURI = request.getRequestURI();
boolean isEnabled; boolean isEnabled;

View File

@ -25,23 +25,23 @@ public class ExternalAppDepConfig {
private final Map<String, List<String>> commandToGroupMapping; private final Map<String, List<String>> commandToGroupMapping;
public ExternalAppDepConfig( public ExternalAppDepConfig(
EndpointConfiguration endpointConfiguration, RuntimePathConfig runtimePathConfig) { EndpointConfiguration endpointConfiguration, RuntimePathConfig runtimePathConfig) {
this.endpointConfiguration = endpointConfiguration; this.endpointConfiguration = endpointConfiguration;
weasyprintPath = runtimePathConfig.getWeasyPrintPath(); weasyprintPath = runtimePathConfig.getWeasyPrintPath();
unoconvPath = runtimePathConfig.getUnoConvertPath(); unoconvPath = runtimePathConfig.getUnoConvertPath();
commandToGroupMapping = commandToGroupMapping =
new HashMap<>() { new HashMap<>() {
{ {
put("soffice", List.of("LibreOffice")); put("soffice", List.of("LibreOffice"));
put(weasyprintPath, List.of("Weasyprint")); put(weasyprintPath, List.of("Weasyprint"));
put("pdftohtml", List.of("Pdftohtml")); put("pdftohtml", List.of("Pdftohtml"));
put(unoconvPath, List.of("Unoconvert")); put(unoconvPath, List.of("Unoconvert"));
put("qpdf", List.of("qpdf")); put("qpdf", List.of("qpdf"));
put("tesseract", List.of("tesseract")); put("tesseract", List.of("tesseract"));
} }
}; };
} }
private boolean isCommandAvailable(String command) { private boolean isCommandAvailable(String command) {
@ -63,8 +63,8 @@ public class ExternalAppDepConfig {
private List<String> getAffectedFeatures(String group) { private List<String> getAffectedFeatures(String group) {
return endpointConfiguration.getEndpointsForGroup(group).stream() return endpointConfiguration.getEndpointsForGroup(group).stream()
.map(endpoint -> formatEndpointAsFeature(endpoint)) .map(endpoint -> formatEndpointAsFeature(endpoint))
.toList(); .toList();
} }
private String formatEndpointAsFeature(String endpoint) { private String formatEndpointAsFeature(String endpoint) {
@ -72,8 +72,8 @@ public class ExternalAppDepConfig {
String feature = endpoint.replace("-", " ").replace("pdf", "PDF").replace("img", "image"); String feature = endpoint.replace("-", " ").replace("pdf", "PDF").replace("img", "image");
// Split into words and capitalize each word // Split into words and capitalize each word
return Arrays.stream(feature.split("\\s+")) return Arrays.stream(feature.split("\\s+"))
.map(word -> capitalizeWord(word)) .map(word -> capitalizeWord(word))
.collect(Collectors.joining(" ")); .collect(Collectors.joining(" "));
} }
private String capitalizeWord(String word) { private String capitalizeWord(String word) {
@ -95,12 +95,12 @@ public class ExternalAppDepConfig {
List<String> affectedFeatures = getAffectedFeatures(group); List<String> affectedFeatures = getAffectedFeatures(group);
endpointConfiguration.disableGroup(group); endpointConfiguration.disableGroup(group);
log.warn( log.warn(
"Missing dependency: {} - Disabling group: {} (Affected features: {})", "Missing dependency: {} - Disabling group: {} (Affected features: {})",
command, command,
group, group,
affectedFeatures != null && !affectedFeatures.isEmpty() affectedFeatures != null && !affectedFeatures.isEmpty()
? String.join(", ", affectedFeatures) ? String.join(", ", affectedFeatures)
: "unknown"); : "unknown");
} }
} }
} }
@ -123,9 +123,9 @@ public class ExternalAppDepConfig {
endpointConfiguration.disableGroup("Python"); endpointConfiguration.disableGroup("Python");
endpointConfiguration.disableGroup("OpenCV"); endpointConfiguration.disableGroup("OpenCV");
log.warn( log.warn(
"Missing dependency: Python - Disabling Python features: {} and OpenCV features: {}", "Missing dependency: Python - Disabling Python features: {} and OpenCV features: {}",
String.join(", ", pythonFeatures), String.join(", ", pythonFeatures),
String.join(", ", openCVFeatures)); String.join(", ", openCVFeatures));
} else { } else {
// If Python is available, check for OpenCV // If Python is available, check for OpenCV
try { try {
@ -141,16 +141,16 @@ public class ExternalAppDepConfig {
List<String> openCVFeatures = getAffectedFeatures("OpenCV"); List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup("OpenCV"); endpointConfiguration.disableGroup("OpenCV");
log.warn( log.warn(
"OpenCV not available in Python - Disabling OpenCV features: {}", "OpenCV not available in Python - Disabling OpenCV features: {}",
String.join(", ", openCVFeatures)); String.join(", ", openCVFeatures));
} }
} catch (Exception e) { } catch (Exception e) {
List<String> openCVFeatures = getAffectedFeatures("OpenCV"); List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup("OpenCV"); endpointConfiguration.disableGroup("OpenCV");
log.warn( log.warn(
"Error checking OpenCV: {} - Disabling OpenCV features: {}", "Error checking OpenCV: {} - Disabling OpenCV features: {}",
e.getMessage(), e.getMessage(),
String.join(", ", openCVFeatures)); String.join(", ", openCVFeatures));
} }
} }
endpointConfiguration.logDisabledEndpointsSummary(); endpointConfiguration.logDisabledEndpointsSummary();

View File

@ -59,7 +59,7 @@ public class InitialSetup {
public void initEnableCSRFSecurity() throws IOException { public void initEnableCSRFSecurity() throws IOException {
if (GeneralUtils.isVersionHigher( if (GeneralUtils.isVersionHigher(
"0.46.0", applicationProperties.getAutomaticallyGenerated().getAppVersion())) { "0.36.0", applicationProperties.getAutomaticallyGenerated().getAppVersion())) {
Boolean csrf = applicationProperties.getSecurity().getCsrfDisabled(); Boolean csrf = applicationProperties.getSecurity().getCsrfDisabled();
if (!csrf) { if (!csrf) {
GeneralUtils.saveKeyToSettings("security.csrfDisabled", false); GeneralUtils.saveKeyToSettings("security.csrfDisabled", false);

View File

@ -25,11 +25,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
// Handler for external static resources // Handler for external static resources
registry.addResourceHandler("/**") registry.addResourceHandler("/**")
.addResourceLocations( .addResourceLocations(
"file:" + InstallationPathConfig.getStaticPath(), "file:" + InstallationPathConfig.getStaticPath(), "classpath:/static/");
"classpath:/static/"
);
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
// .setCachePeriod(0); // Optional: disable caching // .setCachePeriod(0); // Optional: disable caching
} }
} }

View File

@ -12,7 +12,7 @@
// import jakarta.servlet.http.HttpServletResponse; // import jakarta.servlet.http.HttpServletResponse;
// import jakarta.servlet.http.HttpSession; // import jakarta.servlet.http.HttpSession;
// import lombok.extern.slf4j.Slf4j; // import lombok.extern.slf4j.Slf4j;
// import stirling.software.common.util.RequestUriUtils; // import stirling.software.SPDF.utils.RequestUriUtils;
// //
//// @Component //// @Component
// @Slf4j // @Slf4j

View File

@ -36,9 +36,9 @@ public class SettingsController {
public ResponseEntity<String> updateApiKey(@RequestBody Boolean enabled) throws IOException { public ResponseEntity<String> updateApiKey(@RequestBody Boolean enabled) throws IOException {
if (applicationProperties.getSystem().getEnableAnalytics() != null) { if (applicationProperties.getSystem().getEnableAnalytics() != null) {
return ResponseEntity.status(HttpStatus.ALREADY_REPORTED) return ResponseEntity.status(HttpStatus.ALREADY_REPORTED)
.body( .body(
"Setting has already been set, To adjust please edit " "Setting has already been set, To adjust please edit "
+ InstallationPathConfig.getSettingsPath()); + InstallationPathConfig.getSettingsPath());
} }
GeneralUtils.saveKeyToSettings("system.enableAnalytics", enabled); GeneralUtils.saveKeyToSettings("system.enableAnalytics", enabled);
applicationProperties.getSystem().setEnableAnalytics(enabled); applicationProperties.getSystem().setEnableAnalytics(enabled);

View File

@ -27,9 +27,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils; import stirling.software.common.util.WebResponseUtils;
import stirling.software.SPDF.model.api.PDFWithPageNums;
@RestController @RestController
@RequestMapping("/api/v1/general") @RequestMapping("/api/v1/general")

View File

@ -31,11 +31,11 @@ import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
import stirling.software.common.model.PdfMetadata; import stirling.software.common.model.PdfMetadata;
import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.service.PdfMetadataService; import stirling.software.common.service.PdfMetadataService;
import stirling.software.common.util.WebResponseUtils; import stirling.software.common.util.WebResponseUtils;
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
@RestController @RestController
@RequestMapping("/api/v1/general") @RequestMapping("/api/v1/general")

View File

@ -31,9 +31,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.WebResponseUtils; import stirling.software.common.util.WebResponseUtils;
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
@RestController @RestController
@RequestMapping("/api/v1/general") @RequestMapping("/api/v1/general")

View File

@ -23,7 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import stirling.software.common.model.api.GeneralFile; import stirling.software.SPDF.model.api.GeneralFile;
import stirling.software.common.configuration.RuntimePathConfig; import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.ApplicationProperties; import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.service.CustomPDFDocumentFactory; import stirling.software.common.service.CustomPDFDocumentFactory;

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