Compare commits

...

14 Commits

Author SHA1 Message Date
Dario Ghunney Ware
24ccde0ca0 updated build.gradle 2025-06-02 15:04:27 +01:00
Dario Ghunney Ware
fc63a90620 added back activeSecurity bean 2025-06-02 14:39:55 +01:00
Dario Ghunney Ware
6a17bc0cd3 updating LICENSE-proprietary 2025-06-02 11:44:05 +01:00
Dario Ghunney Ware
d2c5d28473 DOCKER_ENABLE_SECURITY > ADDITIONAL_FEATURES_OFF 2025-06-02 11:44:05 +01:00
Dario Ghunney Ware
9c7ae0be5f added proprietary module to base packages for scanning
clean up
2025-06-02 11:44:05 +01:00
Dario Ghunney Ware
1401d7011f updating license 2025-06-02 11:44:05 +01:00
Dario Ghunney Ware
e48f0fc526 moving security package and relevant files over to proprietary 2025-06-02 11:44:05 +01:00
Dario Ghunney Ware
e2685aa93f creating new proprietary module 2025-06-02 11:44:05 +01:00
Dario Ghunney Ware
5d1d8138dc wip - making db and sessions conditional 2025-06-02 09:56:53 +01:00
Balázs Szücs
631c4fef0b
Added scan filter feature (#3530)
# Description of Changes

Please provide a summary of the changes, including:

This pull request introduces the "Fake Scan" feature, which simulates
scanned PDFs with customizable settings. The changes include the removal
of a work-in-progress controller, the addition of a new request model,
and updates to the frontend to support the feature.

### Backend Changes:

* **Removed the unfinished `FakeScanControllerWIP`:** The entire
`FakeScanControllerWIP` class, which contained unimplemented and
experimental code for processing PDFs, has been removed. This cleanup
eliminates unused code and dependencies. Some of the original code of
removed file was ported to the new Controller.
* **Added `FakeScanRequest` model:** Introduced a new model class
`FakeScanRequest` to handle input parameters for the "Fake Scan"
feature. It includes fields for file input, quality, rotation,
colorspace, and other advanced settings, with validation and default
values.

### Frontend Changes:

* **Localization updates for the "Fake Scan" feature:** Added new
localization keys for the "Fake Scan" feature, including titles,
descriptions, and advanced settings options like quality, rotation, and
colorspace.
* **Added "Fake Scan" card to the homepage

### Pictures:
Front-end

![image](https://github.com/user-attachments/assets/e8e2fcac-9f64-4541-8518-04330644030f)

Example document (based on defaults; can be drastically changed
according to need.):

![image](https://github.com/user-attachments/assets/9f9cc386-6eb4-431a-b1d7-ca260edfa0c1)

### Quirks/known issues
- Performance: It might take even reasonable hardware to convert bigger
pdf >500KB more than a few minutes.
- Yellowish filter applies to the whole document and also incl to the
background. (not desirable in some instances)
- There is some randomness involved in the default preset, helps imitate
scan but some user might find it annoying. (but it can be disabled
through advanced settings).
- Some features might confusing to people with no additional context.

Closes #458
---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-05-31 16:26:52 +01:00
stirlingbot[bot]
209c76d885
🌐 Sync Translations + Update README Progress Table (#3616)
### Description of Changes

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

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

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

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

---

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

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

Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
2025-05-31 12:31:25 +01:00
Ludy
3293d0d8a1
Fix Tibetan locale code to bo_CN and update translation ignore configurations (#3614)
# Description of Changes

## This PR also serves as a test for PR #3615.

### PR #3615 must first be merged to complete the test.

---

- **What was changed**  
- Replaced Tibetan locale code in README (`README.md`) from `zh_BO` to
`bo_CN`.
- Renamed resource file `messages_zh_BO.properties` to
`messages_bo_CN.properties` and updated its internal keys/translations.
- Updated the HTML fragment (`templates/fragments/languages.html`) to
reference `bo_CN` instead of `zh_BO`.
- Added a `[bo_CN]` section in `scripts/ignore_translation.toml` and
expanded ignore rules across multiple language sections to cover
additional codes.
- Enhanced `counter_translation.py` error handling: now catches
`ValueError` as `e` and logs file path and line number for easier
debugging.

- **Why the change was made**  
- The proper locale identifier for Tibetan is `bo_CN`, aligning with
[Localizely’s standard](https://localizely.com/locale-code/bo-CN/).
- Ensures consistency across code, resources, and templates so the
Tibetan translation loads correctly.
- Expanded ignore lists prevent false positives in translation coverage
checks, and improved error logging aids maintenance of the translation
scripts.

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-05-31 12:24:02 +01:00
Ludy
45462dc5d4
Use setup-bot token for GitHub Actions and fix GH_APP_ID secret reference (#3615)
# Description of Changes

Please provide a summary of the changes, including:

- **What was changed**  
- In **`.github/workflows/check_properties.yml`**, each
`actions/github-script` step now uses the GitHub App token output (`${{
steps.setup-bot.outputs.token }}`) instead of relying on the default
`secrets.GITHUB_TOKEN`.
- In **`.github/workflows/sync_files.yml`**, the `app-id` input for the
`setup-bot` action was corrected to use `${{ secrets.GH_APP_ID }}`
instead of `${{ vars.GH_APP_ID }}`.

- **Why the change was made**  
- To ensure all workflow steps authenticate through the GitHub App with
least-privilege tokens, improving security and avoiding permission
issues with the default token or inaccessible repo variables.
- To maintain consistency across workflows by centralizing
authentication to the App’s token output.


---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-05-31 12:23:20 +01:00
albanobattistella
c0e93cd5e5
Update messages_it_IT.properties (#3612)
# Description of Changes

Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
2025-05-29 16:01:58 +01:00
123 changed files with 2738 additions and 1302 deletions

View File

@ -84,7 +84,7 @@ jobs:
core.setOutput('repository', repository);
core.setOutput('ref', pr.head.ref);
- name: Check for security/login flag
id: check-security-flag
env:
@ -157,8 +157,10 @@ jobs:
run: |
if [ "${{ needs.check-comment.outputs.enable_security }}" == "true" ]; then
export DOCKER_ENABLE_SECURITY=true
export ADDITIONAL_FEATURES_OFF=false
else
export DOCKER_ENABLE_SECURITY=false
export ADDITIONAL_FEATURES_OFF=true
fi
./gradlew clean build
env:
@ -223,7 +225,8 @@ jobs:
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "${DOCKER_SECURITY}"
DOCKER_ENABLE_SECURITY: "${DOCKER_SECURITY}" # todo: change DOCKER_SECURITY?
ADDITIONAL_FEATURES_OFF: "${DOCKER_SECURITY}"
SECURITY_ENABLELOGIN: "${LOGIN_SECURITY}"
SYSTEM_DEFAULTLOCALE: en-GB
UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}"
@ -250,7 +253,7 @@ jobs:
docker-compose pull
docker-compose up -d
ENDSSH
# Set output for use in PR comment
echo "security_status=${SECURITY_STATUS}" >> $GITHUB_ENV

View File

@ -41,11 +41,13 @@ jobs:
run: ./gradlew clean build
env:
DOCKER_ENABLE_SECURITY: false
ADDITIONAL_FEATURES_OFF: true
- name: Build with Gradle and with spring security
run: ./gradlew clean build
env:
DOCKER_ENABLE_SECURITY: true
ADDITIONAL_FEATURES_OFF: false
- name: Upload Test Reports
if: always()

View File

@ -36,6 +36,7 @@ jobs:
id: get-pr-data
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const prNumber = context.payload.pull_request.number;
const repoOwner = context.payload.repository.owner.login;
@ -56,7 +57,7 @@ jobs:
- name: Fetch PR changed files
id: fetch-pr-changes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.setup-bot.outputs.token }}
run: |
echo "Fetching PR changed files..."
echo "Getting list of changed files from PR..."
@ -66,6 +67,7 @@ jobs:
id: determine-file
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const fs = require("fs");
const path = require("path");
@ -206,6 +208,7 @@ jobs:
if: env.SCRIPT_OUTPUT != ''
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ steps.setup-bot.outputs.token }}
script: |
const { GITHUB_REPOSITORY, SCRIPT_OUTPUT } = process.env;
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');

View File

@ -49,11 +49,16 @@ jobs:
strategy:
matrix:
enable_security: [true, false]
disable_security: [true, false]
include:
- enable_security: true
file_suffix: "-with-login"
- enable_security: false
file_suffix: ""
- disable_security: true
file_suffix: ""
- disable_security: false
file_suffix: "-with-login"
steps:
- name: Harden Runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
@ -76,6 +81,7 @@ jobs:
run: ./gradlew clean createExe
env:
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
ADDITIONAL_FEATURES_OFF: ${{ matrix.disable_security }}
STIRLING_PDF_DESKTOP_UI: false
- name: Rename binaries
@ -172,6 +178,7 @@ jobs:
run: ./gradlew build jpackage -x test --info
env:
DOCKER_ENABLE_SECURITY: false
ADDITIONAL_FEATURES_OFF: true
STIRLING_PDF_DESKTOP_UI: true
BROWSER_OPEN: true

View File

@ -38,6 +38,7 @@ jobs:
run: ./gradlew clean build
env:
DOCKER_ENABLE_SECURITY: false
ADDITIONAL_FEATURES_OFF: true
STIRLING_PDF_DESKTOP_UI: false
- name: Install cosign

View File

@ -14,11 +14,16 @@ jobs:
strategy:
matrix:
enable_security: [true, false]
disable_security: [true, false]
include:
- enable_security: true
file_suffix: "-with-login"
- enable_security: false
file_suffix: ""
- disable_security: true
file_suffix: ""
- disable_security: false
file_suffix: "-with-login"
outputs:
version: ${{ steps.versionNumber.outputs.versionNumber }}
steps:
@ -43,6 +48,7 @@ jobs:
run: ./gradlew clean createExe
env:
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
ADDITIONAL_FEATURES_OFF: ${{ matrix.disable_security }}
STIRLING_PDF_DESKTOP_UI: false
- name: Get version number

View File

@ -34,6 +34,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
DOCKER_ENABLE_SECURITY: true
ADDITIONAL_FEATURES_OFF: false
STIRLING_PDF_DESKTOP_UI: true
run: |
./gradlew clean build sonar \

View File

@ -30,7 +30,7 @@ jobs:
id: setup-bot
uses: ./.github/actions/setup-bot
with:
app-id: ${{ vars.GH_APP_ID }}
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Set up Python

View File

@ -29,6 +29,7 @@ jobs:
run: ./gradlew clean build
env:
DOCKER_ENABLE_SECURITY: false
ADDITIONAL_FEATURES_OFF: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
@ -77,6 +78,7 @@ jobs:
- /stirling/test-${{ github.sha }}/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
ADDITIONAL_FEATURES_OFF: "true"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en-GB
UI_APPNAME: "Stirling-PDF Test"

View File

@ -50,8 +50,10 @@
".vscode/",
"bin/",
"common/bin/",
"proprietary/bin/",
"build/",
"common/build/",
"proprietary/build/",
"configs/",
"customFiles/",
"docs/",
@ -66,6 +68,7 @@
".gitattributes",
".gitignore",
"common/.gitignore",
"proprietary/.gitignore",
".pre-commit-config.yaml",
],
// Enables signature help in Java.

View File

@ -55,7 +55,7 @@ Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, do
Visit the [Lombok website](https://projectlombok.org/setup/) for installation instructions specific to your IDE.
5. Add environment variable
For local testing, you should generally be testing the full 'Security' version of Stirling-PDF. To do this, you must add the environment flag DOCKER_ENABLE_SECURITY=true to your system and/or IDE build/run step.
For local testing, you should generally be testing the full 'Security' version of Stirling-PDF. To do this, you must add the environment flag DOCKER_ENABLE_SECURITY=true or ADDITIONAL_FEATURES_OFF=false to your system and/or IDE build/run step.
## 4. Project Structure
@ -142,6 +142,7 @@ services:
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "true"
PUID: 1002
PGID: 1002
@ -171,6 +172,7 @@ Stirling-PDF uses different Docker images for various configurations. The build
```bash
export DOCKER_ENABLE_SECURITY=false # or true for security-enabled builds
export ADDITIONAL_FEATURES_OFF=true # or false for security-enabled builds
```
2. Build the project with Gradle:
@ -197,6 +199,7 @@ Stirling-PDF uses different Docker images for various configurations. The build
```bash
export DOCKER_ENABLE_SECURITY=true
export ADDITIONAL_FEATURES_OFF=false
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat .
```

View File

@ -24,6 +24,7 @@ LABEL org.opencontainers.image.keywords="PDF, manipulation, merge, split, conver
# Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \
ADDITIONAL_FEATURES_OFF=true \
VERSION_TAG=$VERSION_TAG \
JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \
JAVA_CUSTOM_OPTS="" \

View File

@ -5,6 +5,8 @@ COPY build.gradle .
COPY settings.gradle .
COPY gradlew .
COPY gradle gradle/
COPY common/build.gradle common/.
COPY proprietary/build.gradle proprietary/.
RUN ./gradlew build -x spotlessApply -x spotlessCheck -x test -x sonarqube || return 0
# Set the working directory
@ -13,8 +15,9 @@ WORKDIR /app
# Copy the entire project to the working directory
COPY . .
# Build the application with DOCKER_ENABLE_SECURITY=false
# Build the application with DOCKER_ENABLE_SECURITY=true/ADDITIONAL_FEATURES_OFF=false
RUN DOCKER_ENABLE_SECURITY=true \
ADDITIONAL_FEATURES_OFF=false \
STIRLING_PDF_DESKTOP_UI=false \
./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube
@ -31,6 +34,7 @@ ARG VERSION_TAG
# Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \
ADDITIONAL_FEATURES_OFF=true \
VERSION_TAG=$VERSION_TAG \
JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \
JAVA_CUSTOM_OPTS="" \

View File

@ -5,6 +5,7 @@ ARG VERSION_TAG
# Set Environment Variables
ENV DOCKER_ENABLE_SECURITY=false \
ADDITIONAL_FEATURES_OFF=true \
HOME=/home/stirlingpdfuser \
VERSION_TAG=$VERSION_TAG \
JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \

View File

@ -1,6 +1,13 @@
MIT License
Copyright (c) 2024 Stirling Tools
Copyright (c) 2025 Stirling PDF Inc.
Portions of this software are licensed as follows:
* All content that resides under the "proprietary/" directory of this repository,
if that directory exists, is licensed under the license defined in "proprietary/LICENSE".
* Content outside of the above mentioned directories or restrictions above is
available under the MIT License as defined below.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

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

View File

@ -51,25 +51,8 @@ licenseReport {
sourceSets {
main {
java {
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
exclude "stirling/software/SPDF/config/interfaces/DatabaseInterface.java"
exclude "stirling/software/SPDF/config/security/**"
exclude "stirling/software/SPDF/controller/api/DatabaseController.java"
exclude "stirling/software/SPDF/controller/api/EmailController.java"
exclude "stirling/software/SPDF/controller/api/H2SQLCondition.java"
exclude "stirling/software/SPDF/controller/api/UserController.java"
exclude "stirling/software/SPDF/controller/web/AccountWebController.java"
exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java"
exclude "stirling/software/SPDF/model/api/Email.java"
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java"
exclude "stirling/software/SPDF/model/AttemptCounter.java"
exclude "stirling/software/SPDF/model/Authority.java"
exclude "stirling/software/SPDF/model/exception/BackupNotFoundException.java"
exclude "stirling/software/SPDF/model/exception/NoProviderFoundException.java"
exclude "stirling/software/SPDF/model/PersistentLogin.java"
exclude "stirling/software/SPDF/model/SessionEntity.java"
exclude "stirling/software/SPDF/model/User.java"
exclude "stirling/software/SPDF/repository/**"
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false" || System.getenv("ADDITIONAL_FEATURES_OFF") == "true") {
exclude "stirling/software/proprietary/security/**"
}
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
@ -81,11 +64,8 @@ sourceSets {
test {
java {
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
exclude "stirling/software/SPDF/config/security/**"
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationTokenTest.java"
exclude "stirling/software/SPDF/controller/api/EmailControllerTest.java"
exclude "stirling/software/SPDF/repository/**"
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false" || System.getenv("ADDITIONAL_FEATURES_OFF") == "true") {
exclude "stirling/software/proprietary/security/**"
}
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
@ -290,8 +270,6 @@ tasks.register('jpackageMacX64') {
}
}
//jpackage.finalizedBy(jpackageMacX64)
tasks.register('downloadTempJre') {
group = 'distribution'
description = 'Downloads and extracts a temporary JRE'
@ -376,6 +354,7 @@ spotless {
java {
target sourceSets.main.allJava
target project(':common').sourceSets.main.allJava
target project(':proprietary').sourceSets.main.allJava
googleJavaFormat("1.27.0").aosp().reorderImports(false)
@ -441,43 +420,16 @@ dependencies {
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-web:$springBootVersion")
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$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'
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") {
implementation 'io.micrometer:micrometer-registry-prometheus'
implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.3.RELEASE"
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
implementation "org.springframework.boot:spring-boot-starter-mail:$springBootVersion"
implementation "org.springframework.session:spring-session-core:3.5.0"
implementation "org.springframework:spring-jdbc:6.2.7"
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
// Don't upgrade h2database
runtimeOnly "com.h2database:h2:2.3.232"
runtimeOnly "org.postgresql:postgresql:42.7.5"
constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
}
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
implementation 'com.coveo:saml-client:5.0.0'
}
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
if (System.getenv("DOCKER_ENABLE_SECURITY") != "false" || System.getenv("ADDITIONAL_FEATURES_OFF") == "false") {
implementation project(':proprietary')
}
// Batik
implementation "org.apache.xmlgraphics:batik-all:1.19"
@ -485,10 +437,12 @@ dependencies {
// 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-jpeg:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
@ -496,24 +450,18 @@ dependencies {
// 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-tiff:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$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
// 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:pdfbox:$pdfboxVersion")
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion")
// https://mvnrepository.com/artifact/technology.tabula/tabula
@ -537,7 +485,6 @@ dependencies {
// 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")
@ -547,6 +494,7 @@ dependencies {
// 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 {

View File

@ -30,19 +30,19 @@ dependencyManagement {
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
implementation 'com.fathzer:javaluator:3.0.6'
implementation 'com.posthog.java:posthog:1.2.0'
implementation 'io.github.pixee:java-security-toolkit:1.2.1'
implementation 'org.apache.commons:commons-lang3:3.17.0'
implementation 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
implementation "org.apache.pdfbox:pdfbox:$pdfboxVersion"
implementation 'jakarta.servlet:jakarta.servlet-api:6.0.0'
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6"
api 'org.springframework.boot:spring-boot-starter-web'
api 'org.springframework.boot:spring-boot-starter-thymeleaf'
api 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
api 'com.fathzer:javaluator:3.0.6'
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 'com.drewnoakes:metadata-extractor:2.19.0' // Image metadata extractor
api 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
api "org.apache.pdfbox:pdfbox:$pdfboxVersion"
api 'jakarta.servlet:jakarta.servlet-api:6.0.0'
api 'org.snakeyaml:snakeyaml-engine:2.9'
api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6"
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"

View File

@ -10,6 +10,7 @@ import java.util.Properties;
import java.util.function.Predicate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
@ -146,8 +147,16 @@ public class AppConfig {
}
}
@ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration")
@Bean(name = "activeSecurity")
@ConditionalOnClass(
name = "stirling.software.proprietary.security.configuration.SecurityConfiguration")
public boolean activeSecurity() {
return true;
}
@Bean(name = "missingActiveSecurity")
@ConditionalOnMissingClass(
"stirling.software.proprietary.security.configuration.SecurityConfiguration")
public boolean missingActiveSecurity() {
return false;
}

View File

@ -21,6 +21,7 @@ services:
- ../testing/allEndpointsRemovedSettings.yml:/configs/settings.yml:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "false"
PUID: 1002
PGID: 1002

View File

@ -21,6 +21,7 @@ services:
- ./stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "false"
PUID: 1002
PGID: 1002

View File

@ -19,6 +19,7 @@ services:
- ./stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "false"
PUID: 1002
PGID: 1002

View File

@ -19,6 +19,7 @@ services:
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "true"
SECURITY_OAUTH2_ENABLED: "true"
SECURITY_OAUTH2_AUTOCREATEUSER: "true" # This is set to true to allow auto-creation of non-existing users in Stirling-PDF

View File

@ -19,6 +19,7 @@ services:
- ./stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "true"
PUID: 1002
PGID: 1002

View File

@ -19,6 +19,7 @@ services:
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "true"
SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF-Lite

View File

@ -18,6 +18,7 @@ services:
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
ADDITIONAL_FEATURES_OFF: "true"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en-US
UI_APPNAME: Stirling-PDF-Ultra-lite

View File

@ -19,6 +19,7 @@ services:
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
ADDITIONAL_FEATURES_OFF: "true"
SECURITY_ENABLELOGIN: "false"
LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID"
SYSTEM_DEFAULTLOCALE: en-US

View File

@ -19,6 +19,7 @@ services:
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
ADDITIONAL_FEATURES_OFF: "false"
SECURITY_ENABLELOGIN: "true"
PUID: 1002
PGID: 1002

196
proprietary/.gitignore vendored Normal file
View File

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

View File

@ -0,0 +1,51 @@
Stirling PDF User License
Copyright (c) 2025 Stirling PDF Inc.
License Scope & Usage Rights
Production use of the Stirling PDF Software is only permitted with a valid Stirling PDF User License.
For purposes of this license, “the Software” refers to the Stirling PDF application and any associated documentation files
provided by Stirling PDF Inc. You or your organization may not use the Software in production, at scale, or for business-critical
processes unless you have agreed to, and remain in compliance with, the Stirling PDF Subscription Terms of Service
(https://www.stirlingpdf.com/terms) or another valid agreement with Stirling PDF, and hold an active User License subscription
covering the appropriate number of licensed users.
Trial and Minimal Use
You may use the Software without a paid subscription for the sole purposes of internal trial, evaluation, or minimal use, provided that:
* Use is limited to the capabilities and restrictions defined by the Software itself;
* You do not copy, distribute, sublicense, reverse-engineer, or use the Software in client-facing or commercial contexts.
Continued use beyond this scope requires a valid Stirling PDF User License.
Modifications and Derivative Works
You may modify the Software only for development or internal testing purposes. Any such modifications or derivative works:
* May not be deployed in production environments without a valid User License;
* May not be distributed or sublicensed;
* Remain the intellectual property of Stirling PDF and/or its licensors;
* May only be used, copied, or exploited in accordance with the terms of a valid Stirling PDF User License subscription.
Prohibited Actions
Unless explicitly permitted by a paid license or separate agreement, you may not:
* Use the Software in production environments;
* Copy, merge, distribute, sublicense, or sell the Software;
* Remove or alter any licensing or copyright notices;
* Circumvent access restrictions or licensing requirements.
Third-Party Components
The Stirling PDF Software may include components subject to separate open source licenses. Such components remain governed by
their original license terms as provided by their respective owners.
Disclaimer
THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

67
proprietary/build.gradle Normal file
View File

@ -0,0 +1,67 @@
plugins {
id 'java-library'
id 'io.spring.dependency-management' version '1.1.7'
}
repositories {
mavenCentral()
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 {
implementation project(':common')
api 'org.springframework:spring-jdbc'
api 'org.springframework:spring-webmvc'
api 'org.springframework.session:spring-session-core'
api "org.springframework.security:spring-security-core:$springSecuritySamlVersion"
api "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
api 'org.springframework.boot:spring-boot-starter-jetty'
api 'org.springframework.boot:spring-boot-starter-security'
api 'org.springframework.boot:spring-boot-starter-data-jpa'
api 'org.springframework.boot:spring-boot-starter-oauth2-client'
api 'org.springframework.boot:spring-boot-starter-mail'
api 'io.swagger.core.v3:swagger-core-jakarta:2.2.30'
implementation 'com.bucket4j:bucket4j_jdk17-core:8.14.0'
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
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'
api 'io.micrometer:micrometer-registry-prometheus'
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
runtimeOnly 'com.h2database:h2:2.3.232' // Don't upgrade h2database
runtimeOnly 'org.postgresql:postgresql:42.7.5'
constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
}
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') {}

View File

@ -1,8 +1,11 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
@ -10,14 +13,9 @@ import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.User;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.service.LoginAttemptService;
import stirling.software.proprietary.security.service.UserService;
@Slf4j
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

View File

@ -1,19 +1,17 @@
package stirling.software.SPDF.config.security;
import java.io.IOException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
package stirling.software.proprietary.security;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import stirling.software.common.util.RequestUriUtils;
import stirling.software.proprietary.security.service.LoginAttemptService;
import stirling.software.proprietary.security.service.UserService;
@Slf4j
public class CustomAuthenticationSuccessHandler

View File

@ -1,35 +1,30 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security;
import com.coveo.saml.SamlClient;
import com.coveo.saml.SamlException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import com.coveo.saml.SamlClient;
import com.coveo.saml.SamlException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.SPDFApplication;
import stirling.software.SPDF.config.security.saml2.CertificateUtils;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.common.model.oauth2.KeycloakProvider;
import stirling.software.common.util.UrlUtils;
import stirling.software.proprietary.security.saml2.CertificateUtils;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
@Slf4j
@RequiredArgsConstructor
@ -38,6 +33,7 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
public static final String LOGOUT_PATH = "/login?logout=true";
private final ApplicationProperties applicationProperties;
private final AppConfig appConfig;
@Override
public void onLogoutSuccess(
@ -102,7 +98,7 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
// Set service provider keys for the SamlClient
samlClient.setSPKeys(certificate, privateKey);
// Redirect to identity provider for logout
// Redirect to identity provider for logout. todo: add relay state
samlClient.redirectToIdentityProvider(response, null, nameIdValue);
} catch (Exception e) {
log.error(
@ -172,11 +168,11 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
}
}
private static SamlClient getSamlClient(
private SamlClient getSamlClient(
String registrationId, SAML2 samlConf, List<X509Certificate> certificates)
throws SamlException {
String serverUrl =
SPDFApplication.getStaticBaseUrl() + ":" + SPDFApplication.getStaticPort();
appConfig.getBaseUrl() + ":" + appConfig.getServerPort();
String relyingPartyIdentifier =
serverUrl + "/saml2/service-provider-metadata/" + registrationId;

View File

@ -1,19 +1,16 @@
package stirling.software.SPDF.config.security;
import java.sql.SQLException;
import java.util.UUID;
import org.springframework.stereotype.Component;
package stirling.software.proprietary.security;
import jakarta.annotation.PostConstruct;
import java.sql.SQLException;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.model.Role;
import org.springframework.stereotype.Component;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.common.model.enumeration.Role;
import stirling.software.proprietary.security.service.DatabaseServiceInterface;
import stirling.software.proprietary.security.service.UserService;
@Slf4j
@Component
@ -24,7 +21,7 @@ public class InitialSecuritySetup {
private final ApplicationProperties applicationProperties;
private final DatabaseInterface databaseService;
private final DatabaseServiceInterface databaseService;
@PostConstruct
public void init() {

View File

@ -1,9 +1,9 @@
package stirling.software.SPDF.config.security;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
package stirling.software.proprietary.security;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import stirling.software.proprietary.security.filter.IPRateLimitingFilter;
@Component
@RequiredArgsConstructor

View File

@ -1,15 +1,16 @@
package stirling.software.SPDF.config.security.database;
package stirling.software.proprietary.security.configuration;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException;
@ -17,14 +18,14 @@ import stirling.software.common.model.exception.UnsupportedProviderException;
@Slf4j
@Getter
@Configuration
@EnableJpaRepositories(basePackages = "stirling.software.proprietary.security.database.repository")
@EntityScan({"stirling.software.proprietary.security.model"})
public class DatabaseConfig {
public final String DATASOURCE_DEFAULT_URL;
public static final String DATASOURCE_URL_TEMPLATE = "jdbc:%s://%s:%4d/%s";
public static final String DEFAULT_DRIVER = "org.h2.Driver";
public static final String DEFAULT_USERNAME = "sa";
public static final String POSTGRES_DRIVER = "org.postgresql.Driver";
private final ApplicationProperties.Datasource datasource;
private final boolean runningProOrHigher;
@ -54,30 +55,41 @@ public class DatabaseConfig {
public DataSource dataSource() throws UnsupportedProviderException {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
if (!runningProOrHigher) {
if (!runningProOrHigher || !datasource.isEnableCustomDatabase()) {
return useDefaultDataSource(dataSourceBuilder);
}
if (!datasource.isEnableCustomDatabase()) {
return useDefaultDataSource(dataSourceBuilder);
}
return useCustomDataSource(dataSourceBuilder);
}
private DataSource useDefaultDataSource(DataSourceBuilder<?> dataSourceBuilder) {
log.info("Using default H2 database");
dataSourceBuilder.url(DATASOURCE_DEFAULT_URL)
.driverClassName(DatabaseDriver.H2.getDriverClassName())
.username(DEFAULT_USERNAME);
return dataSourceBuilder.build();
}
@ConditionalOnBooleanProperty(name = "premium.enabled")
private DataSource useCustomDataSource(DataSourceBuilder<?> dataSourceBuilder) throws UnsupportedProviderException {
log.info("Using custom database configuration");
if (!datasource.getCustomDatabaseUrl().isBlank()) {
if (datasource.getCustomDatabaseUrl().contains("postgresql")) {
dataSourceBuilder.driverClassName(POSTGRES_DRIVER);
dataSourceBuilder.driverClassName(DatabaseDriver.POSTGRESQL.getDriverClassName());
}
dataSourceBuilder.url(datasource.getCustomDatabaseUrl());
} else {
dataSourceBuilder.driverClassName(getDriverClassName(datasource.getType()));
dataSourceBuilder.url(
generateCustomDataSourceUrl(
datasource.getType(),
datasource.getHostName(),
datasource.getPort(),
datasource.getName()));
generateCustomDataSourceUrl(
datasource.getType(),
datasource.getHostName(),
datasource.getPort(),
datasource.getName()));
}
dataSourceBuilder.username(datasource.getUsername());
dataSourceBuilder.password(datasource.getPassword());
@ -85,15 +97,6 @@ public class DatabaseConfig {
return dataSourceBuilder.build();
}
private DataSource useDefaultDataSource(DataSourceBuilder<?> dataSourceBuilder) {
log.info("Using default H2 database");
dataSourceBuilder.url(DATASOURCE_DEFAULT_URL);
dataSourceBuilder.username(DEFAULT_USERNAME);
return dataSourceBuilder.build();
}
/**
* Generate the URL the <code>DataSource</code> will use to connect to the database
*
@ -123,11 +126,11 @@ public class DatabaseConfig {
switch (driver) {
case H2 -> {
log.debug("H2 driver selected");
return DEFAULT_DRIVER;
return DatabaseDriver.H2.getDriverClassName();
}
case POSTGRESQL -> {
log.debug("Postgres driver selected");
return POSTGRES_DRIVER;
return DatabaseDriver.POSTGRESQL.getDriverClassName();
}
default -> {
log.warn("{} driver selected", driverName);

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.security.mail;
package stirling.software.proprietary.security.configuration;
import java.util.Properties;
@ -10,7 +10,6 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.ApplicationProperties;
/**

View File

@ -0,0 +1,318 @@
package stirling.software.proprietary.security.configuration;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import stirling.software.common.configuration.AppConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.proprietary.security.CustomAuthenticationFailureHandler;
import stirling.software.proprietary.security.CustomAuthenticationSuccessHandler;
import stirling.software.proprietary.security.CustomLogoutSuccessHandler;
import stirling.software.proprietary.security.database.repository.JPATokenRepositoryImpl;
import stirling.software.proprietary.security.database.repository.PersistentLoginRepository;
import stirling.software.proprietary.security.filter.FirstLoginFilter;
import stirling.software.proprietary.security.filter.IPRateLimitingFilter;
import stirling.software.proprietary.security.filter.UserAuthenticationFilter;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
import stirling.software.proprietary.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticationFailureHandler;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticationSuccessHandler;
import stirling.software.proprietary.security.saml2.CustomSaml2ResponseAuthenticationConverter;
import stirling.software.proprietary.security.service.CustomOAuth2UserService;
import stirling.software.proprietary.security.service.CustomUserDetailsService;
import stirling.software.proprietary.security.service.LoginAttemptService;
import stirling.software.proprietary.security.service.UserService;
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
@Slf4j
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfiguration {
private final CustomUserDetailsService userDetailsService;
private final UserService userService;
private final boolean loginEnabledValue;
private final boolean runningProOrHigher;
private final ApplicationProperties applicationProperties;
private final AppConfig appConfig;
private final UserAuthenticationFilter userAuthenticationFilter;
private final LoginAttemptService loginAttemptService;
private final FirstLoginFilter firstLoginFilter;
private final SessionPersistentRegistry sessionRegistry;
private final PersistentLoginRepository persistentLoginRepository;
private final GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper;
private final RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations;
private final OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver;
public SecurityConfiguration(
PersistentLoginRepository persistentLoginRepository,
CustomUserDetailsService userDetailsService,
@Lazy UserService userService,
@Qualifier("loginEnabled") boolean loginEnabledValue,
@Qualifier("runningProOrHigher") boolean runningProOrHigher,
AppConfig appConfig,
ApplicationProperties applicationProperties,
UserAuthenticationFilter userAuthenticationFilter,
LoginAttemptService loginAttemptService,
FirstLoginFilter firstLoginFilter,
SessionPersistentRegistry sessionRegistry,
@Autowired(required = false) GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper,
@Autowired(required = false)
RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations,
@Autowired(required = false)
OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver) {
this.userDetailsService = userDetailsService;
this.userService = userService;
this.loginEnabledValue = loginEnabledValue;
this.runningProOrHigher = runningProOrHigher;
this.appConfig = appConfig;
this.applicationProperties = applicationProperties;
this.userAuthenticationFilter = userAuthenticationFilter;
this.loginAttemptService = loginAttemptService;
this.firstLoginFilter = firstLoginFilter;
this.sessionRegistry = sessionRegistry;
this.persistentLoginRepository = persistentLoginRepository;
this.oAuth2userAuthoritiesMapper = oAuth2userAuthoritiesMapper;
this.saml2RelyingPartyRegistrations = saml2RelyingPartyRegistrations;
this.saml2AuthenticationRequestResolver = saml2AuthenticationRequestResolver;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
if (applicationProperties.getSecurity().getCsrfDisabled() || !loginEnabledValue) {
http.csrf(csrf -> csrf.disable());
}
if (loginEnabledValue) {
http.addFilterBefore(
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
if (!applicationProperties.getSecurity().getCsrfDisabled()) {
CookieCsrfTokenRepository cookieRepo =
CookieCsrfTokenRepository.withHttpOnlyFalse();
CsrfTokenRequestAttributeHandler requestHandler =
new CsrfTokenRequestAttributeHandler();
requestHandler.setCsrfRequestAttributeName(null);
http.csrf(
csrf ->
csrf.ignoringRequestMatchers(
request -> {
String apiKey = request.getHeader("X-API-KEY");
// If there's no API key, don't ignore CSRF
// (return false)
if (apiKey == null || apiKey.trim().isEmpty()) {
return false;
}
// Validate API key using existing UserService
try {
Optional<User> user =
userService.getUserByApiKey(apiKey);
// If API key is valid, ignore CSRF (return
// true)
// If API key is invalid, don't ignore CSRF
// (return false)
return user.isPresent();
} catch (Exception e) {
// If there's any error validating the API
// key, don't ignore CSRF
return false;
}
})
.csrfTokenRepository(cookieRepo)
.csrfTokenRequestHandler(requestHandler));
}
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
http.sessionManagement(
sessionManagement ->
sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(10)
.maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry)
.expiredUrl("/login?logout=true"));
http.authenticationProvider(daoAuthenticationProvider());
http.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()));
http.logout(
logout ->
logout.logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher("/logout"))
.logoutSuccessHandler(
new CustomLogoutSuccessHandler(applicationProperties, appConfig))
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID", "remember-me"));
http.rememberMe(
rememberMeConfigurer -> // Use the configurator directly
rememberMeConfigurer
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds( // 14 days
14 * 24 * 60 * 60)
.userDetailsService( // Your existing UserDetailsService
userDetailsService)
.useSecureCookie( // Enable secure cookie
true)
.rememberMeParameter( // Form parameter name
"remember-me")
.rememberMeCookieName( // Cookie name
"remember-me")
.alwaysRemember(false));
http.authorizeHttpRequests(
authz ->
authz.requestMatchers(
req -> {
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
// Remove the context path from the URI
String trimmedUri =
uri.startsWith(contextPath)
? uri.substring(
contextPath.length())
: uri;
return trimmedUri.startsWith("/login")
|| trimmedUri.startsWith("/oauth")
|| trimmedUri.startsWith("/saml2")
|| trimmedUri.endsWith(".svg")
|| trimmedUri.startsWith("/register")
|| trimmedUri.startsWith("/error")
|| trimmedUri.startsWith("/images/")
|| trimmedUri.startsWith("/public/")
|| trimmedUri.startsWith("/css/")
|| trimmedUri.startsWith("/fonts/")
|| trimmedUri.startsWith("/js/")
|| trimmedUri.startsWith(
"/api/v1/info/status");
})
.permitAll()
.anyRequest()
.authenticated());
// Handle User/Password Logins
if (applicationProperties.getSecurity().isUserPass()) {
http.formLogin(
formLogin ->
formLogin
.loginPage("/login")
.successHandler(
new CustomAuthenticationSuccessHandler(
loginAttemptService, userService))
.failureHandler(
new CustomAuthenticationFailureHandler(
loginAttemptService, userService))
.defaultSuccessUrl("/")
.permitAll());
}
// Handle OAUTH2 Logins
if (applicationProperties.getSecurity().isOauth2Active()) {
http.oauth2Login(
oauth2 ->
oauth2.loginPage("/oauth2")
/*
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
If user exists, login proceeds as usual. If user does not exist, then it is auto-created but only if 'OAUTH2AutoCreateUser'
is set as true, else login fails with an error message advising the same.
*/
.successHandler(
new CustomOAuth2AuthenticationSuccessHandler(
loginAttemptService,
applicationProperties,
userService))
.failureHandler(
new CustomOAuth2AuthenticationFailureHandler())
. // Add existing Authorities from the database
userInfoEndpoint(
userInfoEndpoint ->
userInfoEndpoint
.oidcUserService(
new CustomOAuth2UserService(
applicationProperties,
userService,
loginAttemptService))
.userAuthoritiesMapper(
oAuth2userAuthoritiesMapper))
.permitAll());
}
// Handle SAML
if (applicationProperties.getSecurity().isSaml2Active() && runningProOrHigher) {
// Configure the authentication provider
OpenSaml4AuthenticationProvider authenticationProvider =
new OpenSaml4AuthenticationProvider();
authenticationProvider.setResponseAuthenticationConverter(
new CustomSaml2ResponseAuthenticationConverter(userService));
http.authenticationProvider(authenticationProvider)
.saml2Login(
saml2 -> {
try {
saml2.loginPage("/saml2")
.relyingPartyRegistrationRepository(
saml2RelyingPartyRegistrations)
.authenticationManager(
new ProviderManager(authenticationProvider))
.successHandler(
new CustomSaml2AuthenticationSuccessHandler(
loginAttemptService,
applicationProperties,
userService))
.failureHandler(
new CustomSaml2AuthenticationFailureHandler())
.authenticationRequestResolver(
saml2AuthenticationRequestResolver);
} catch (Exception e) {
log.error("Error configuring SAML 2 login", e);
throw new RuntimeException(e);
}
});
}
} else {
log.debug("Login is not enabled.");
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
}
return http.build();
}
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Bean
public IPRateLimitingFilter rateLimitingFilter() {
// Example limit TODO add config level
int maxRequestsPerIp = 1000000;
return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp);
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
return new JPATokenRepositoryImpl(persistentLoginRepository);
}
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api;
package stirling.software.proprietary.security.controller.api;
import java.io.IOException;
import java.io.InputStream;
@ -26,8 +26,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.database.DatabaseService;
import stirling.software.proprietary.security.database.H2SQLCondition;
import stirling.software.proprietary.security.service.DatabaseService;
@Slf4j
@Controller

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api;
package stirling.software.proprietary.security.controller.api;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
@ -18,8 +18,8 @@ import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.mail.EmailService;
import stirling.software.SPDF.model.api.Email;
import stirling.software.proprietary.security.model.api.Email;
import stirling.software.proprietary.security.service.EmailService;
/**
* Controller for handling email-related API requests. This controller exposes an endpoint for

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api;
package stirling.software.proprietary.security.controller.api;
import java.io.IOException;
import java.security.Principal;
@ -29,15 +29,15 @@ import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.api.user.UsernameAndPass;
import stirling.software.proprietary.security.model.AuthenticationType;
import stirling.software.common.model.enumeration.Role;
import stirling.software.proprietary.security.model.User;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.proprietary.security.model.api.user.UsernameAndPass;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.proprietary.security.service.UserService;
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
@Controller
@Tag(name = "User", description = "User APIs")

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.web;
package stirling.software.proprietary.security.controller.web;
import static stirling.software.common.util.ProviderUtils.validateProvider;
@ -29,13 +29,7 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.Authority;
import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.SessionEntity;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.UserRepository;
import stirling.software.common.model.enumeration.Role;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
@ -44,6 +38,12 @@ import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.common.model.oauth2.GitHubProvider;
import stirling.software.common.model.oauth2.GoogleProvider;
import stirling.software.common.model.oauth2.KeycloakProvider;
import stirling.software.proprietary.security.database.repository.UserRepository;
import stirling.software.proprietary.security.model.Authority;
import stirling.software.proprietary.security.model.SessionEntity;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
@Controller
@Slf4j

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.web;
package stirling.software.proprietary.security.controller.web;
import java.util.List;
@ -14,8 +14,8 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.security.database.DatabaseService;
import stirling.software.common.model.FileInfo;
import stirling.software.proprietary.security.service.DatabaseService;
@Controller
@Tag(name = "Database Management", description = "Database management and security APIs")

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api;
package stirling.software.proprietary.security.database;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
@ -12,8 +12,12 @@ public class H2SQLCondition implements Condition {
Boolean.parseBoolean(
context.getEnvironment()
.getProperty("system.datasource.enableCustomDatabase"));
if (!enableCustomDatabase) {
return false;
}
String dataSourceType = context.getEnvironment().getProperty("system.datasource.type");
return !enableCustomDatabase
|| (enableCustomDatabase && "h2".equalsIgnoreCase(dataSourceType));
return "h2".equalsIgnoreCase(dataSourceType);
}
}

View File

@ -1,23 +1,19 @@
package stirling.software.SPDF.config.security.database;
package stirling.software.proprietary.security.database;
import java.sql.SQLException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Conditional;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.controller.api.H2SQLCondition;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.proprietary.security.service.DatabaseServiceInterface;
@Component
@Conditional(H2SQLCondition.class)
@RequiredArgsConstructor
public class ScheduledTasks {
private final DatabaseInterface databaseService;
private final DatabaseServiceInterface databaseService;
@Scheduled(cron = "0 0 0 * * ?")
public void performBackup() throws SQLException, UnsupportedProviderException {

View File

@ -1,11 +1,10 @@
package stirling.software.SPDF.repository;
package stirling.software.proprietary.security.database.repository;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.Authority;
import stirling.software.proprietary.security.model.Authority;
@Repository
public interface AuthorityRepository extends JpaRepository<Authority, Long> {

View File

@ -1,12 +1,11 @@
package stirling.software.SPDF.repository;
package stirling.software.proprietary.security.database.repository;
import java.util.Date;
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.transaction.annotation.Transactional;
import stirling.software.SPDF.model.PersistentLogin;
import stirling.software.proprietary.security.model.PersistentLogin;
public class JPATokenRepositoryImpl implements PersistentTokenRepository {

View File

@ -1,9 +1,8 @@
package stirling.software.SPDF.repository;
package stirling.software.proprietary.security.database.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.PersistentLogin;
import stirling.software.proprietary.security.model.PersistentLogin;
@Repository
public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> {

View File

@ -1,17 +1,14 @@
package stirling.software.SPDF.config.security.session;
package stirling.software.proprietary.security.database.repository;
import jakarta.transaction.Transactional;
import java.util.Date;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import jakarta.transaction.Transactional;
import stirling.software.SPDF.model.SessionEntity;
import stirling.software.proprietary.security.model.SessionEntity;
@Repository
public interface SessionRepository extends JpaRepository<SessionEntity, String> {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.repository;
package stirling.software.proprietary.security.database.repository;
import java.util.List;
import java.util.Optional;
@ -7,8 +7,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import stirling.software.SPDF.model.User;
import stirling.software.proprietary.security.model.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config;
package stirling.software.proprietary.security.filter;
import java.io.IOException;

View File

@ -1,26 +1,23 @@
package stirling.software.SPDF.config.security;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
package stirling.software.proprietary.security.filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.User;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import stirling.software.common.util.RequestUriUtils;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.service.UserService;
@Slf4j
@Component

View File

@ -1,14 +1,15 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security.filter;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import stirling.software.common.util.RequestUriUtils;
@RequiredArgsConstructor

View File

@ -1,9 +1,13 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security.filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
@ -16,21 +20,14 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.ApiKeyAuthenticationToken;
import stirling.software.SPDF.model.User;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.proprietary.security.model.ApiKeyAuthenticationToken;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.proprietary.security.service.UserService;
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
@Slf4j
@Component

View File

@ -1,10 +1,17 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security.filter;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.ConsumptionProbe;
import io.github.pixee.security.Newlines;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
@ -13,18 +20,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.ConsumptionProbe;
import io.github.pixee.security.Newlines;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import stirling.software.SPDF.model.Role;
import stirling.software.common.model.enumeration.Role;
@Component
public class UserBasedRateLimitingFilter extends OncePerRequestFilter {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.proprietary.security.model;
import java.util.Collection;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.proprietary.security.model;
public class AttemptCounter {
private int attemptCount;

View File

@ -0,0 +1,6 @@
package stirling.software.proprietary.security.model;
public enum AuthenticationType {
WEB,
SSO
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.proprietary.security.model;
import java.io.Serializable;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.proprietary.security.model;
import java.util.Date;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.proprietary.security.model;
import java.io.Serializable;
import java.util.Date;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model;
package stirling.software.proprietary.security.model;
import java.io.Serializable;
import java.util.HashMap;
@ -14,6 +14,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import stirling.software.common.model.enumeration.Role;
@Entity
@Table(name = "users")

View File

@ -0,0 +1,39 @@
package stirling.software.proprietary.security.model.api;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import stirling.software.common.model.api.GeneralFile;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ConditionalOnProperty(value = "mail.enabled", havingValue = "true", matchIfMissing = false)
public class Email extends GeneralFile {
@Schema(
description = "The recipient's email address",
requiredMode = Schema.RequiredMode.REQUIRED,
format = "email")
private String to;
@Schema(
description = "The subject of the email",
defaultValue = "Stirling Software PDF Notification",
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String subject;
@Schema(
description = "The body of the email",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue =
"This message was automatically generated by Stirling-PDF, an innovative"
+ " solution from Stirling Software. For more information, visit our <a"
+ " href=\"https://stirling-software.com\">website</a>.<br><br>Please do"
+ " not reply directly to this email.")
private String body;
}

View File

@ -0,0 +1,17 @@
package stirling.software.proprietary.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class UpdateUserDetails extends UpdateUserUsername {
@Schema(
description = "new password for user",
format = "password",
requiredMode = Schema.RequiredMode.REQUIRED)
private String newPassword;
}

View File

@ -0,0 +1,14 @@
package stirling.software.proprietary.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class UpdateUserUsername extends UsernameAndPass {
@Schema(description = "new username for user")
private String newUsername;
}

View File

@ -0,0 +1,14 @@
package stirling.software.proprietary.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode
public class Username {
@Schema(description = "username of user", requiredMode = Schema.RequiredMode.REQUIRED)
private String username;
}

View File

@ -0,0 +1,14 @@
package stirling.software.proprietary.security.model.api.user;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class UsernameAndPass extends Username {
@Schema(description = "password of user", format = "password")
private String password;
}

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.model.exception;
package stirling.software.proprietary.security.model.exception;
public class BackupNotFoundException extends RuntimeException {
public BackupNotFoundException(String message) {

View File

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

View File

@ -1,7 +1,10 @@
package stirling.software.SPDF.config.security.oauth2;
package stirling.software.proprietary.security.oauth2;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
@ -10,12 +13,6 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CustomOAuth2AuthenticationFailureHandler
extends SimpleUrlAuthenticationFailureHandler {

View File

@ -1,29 +1,25 @@
package stirling.software.SPDF.config.security.oauth2;
package stirling.software.proprietary.security.oauth2;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.common.util.RequestUriUtils;
import stirling.software.proprietary.security.model.AuthenticationType;
import stirling.software.proprietary.security.service.LoginAttemptService;
import stirling.software.proprietary.security.service.UserService;
@RequiredArgsConstructor
public class CustomOAuth2AuthenticationSuccessHandler

View File

@ -1,15 +1,13 @@
package stirling.software.SPDF.config.security.oauth2;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
import static stirling.software.common.util.ProviderUtils.validateProvider;
import static stirling.software.common.util.ValidationUtils.isStringEmpty;
package stirling.software.proprietary.security.oauth2;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -22,24 +20,24 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.exception.NoProviderFoundException;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.proprietary.security.model.exception.NoProviderFoundException;
import stirling.software.common.model.oauth2.GitHubProvider;
import stirling.software.common.model.oauth2.GoogleProvider;
import stirling.software.common.model.oauth2.KeycloakProvider;
import stirling.software.common.model.oauth2.Provider;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.service.UserService;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
import static stirling.software.common.util.ProviderUtils.validateProvider;
import static stirling.software.common.util.ValidationUtils.isStringEmpty;
@Slf4j
@Configuration
@ConditionalOnProperty(value = "security.oauth2.enabled", havingValue = "true")
@ConditionalOnBooleanProperty("security.oauth2.enabled")
public class OAuth2Configuration {
public static final String REDIRECT_URI_PATH = "{baseUrl}/login/oauth2/code/";
@ -54,7 +52,6 @@ public class OAuth2Configuration {
}
@Bean
@ConditionalOnProperty(value = "security.oauth2.enabled", havingValue = "true")
public ClientRegistrationRepository clientRegistrationRepository()
throws NoProviderFoundException {
List<ClientRegistration> registrations = new ArrayList<>();

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.security.saml2;
package stirling.software.proprietary.security.saml2;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
@ -6,7 +6,6 @@ import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;

View File

@ -1,9 +1,8 @@
package stirling.software.SPDF.config.security.saml2;
package stirling.software.proprietary.security.saml2;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;

View File

@ -1,7 +1,9 @@
package stirling.software.SPDF.config.security.saml2;
package stirling.software.proprietary.security.saml2;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.authentication.ProviderNotFoundException;
import org.springframework.security.core.AuthenticationException;
@ -9,11 +11,6 @@ import org.springframework.security.saml2.core.Saml2Error;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

View File

@ -1,28 +1,24 @@
package stirling.software.SPDF.config.security.saml2;
import java.io.IOException;
import java.sql.SQLException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
package stirling.software.proprietary.security.saml2;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.AuthenticationType;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.common.util.RequestUriUtils;
import stirling.software.proprietary.security.model.AuthenticationType;
import stirling.software.proprietary.security.service.LoginAttemptService;
import stirling.software.proprietary.security.service.UserService;
@AllArgsConstructor
@Slf4j

View File

@ -1,7 +1,12 @@
package stirling.software.SPDF.config.security.saml2;
import java.util.*;
package stirling.software.proprietary.security.saml2;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
@ -12,12 +17,8 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.service.UserService;
@Slf4j
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")

View File

@ -1,10 +1,13 @@
package stirling.software.SPDF.config.security.saml2;
package stirling.software.proprietary.security.saml2;
import jakarta.servlet.http.HttpServletRequest;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -18,19 +21,13 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
@Configuration
@Slf4j
@ConditionalOnProperty(value = "security.saml2.enabled", havingValue = "true")
@RequiredArgsConstructor
@ConditionalOnBooleanProperty("security.saml2.enabled")
public class SAML2Configuration {
private final ApplicationProperties applicationProperties;

View File

@ -1,17 +1,14 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security.service;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.UserRepository;
import stirling.software.common.configuration.interfaces.ShowAdminInterface;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.proprietary.security.database.repository.UserRepository;
import stirling.software.proprietary.security.model.User;
@Service
@RequiredArgsConstructor

View File

@ -1,7 +1,7 @@
package stirling.software.SPDF.config.security.oauth2;
package stirling.software.proprietary.security.service;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
@ -10,15 +10,10 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.User;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.common.model.enumeration.UsernameAttribute;
import stirling.software.proprietary.security.model.User;
@Slf4j
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {

View File

@ -1,8 +1,8 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security.service;
import java.util.Collection;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@ -10,12 +10,9 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.Authority;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.UserRepository;
import stirling.software.proprietary.security.database.repository.UserRepository;
import stirling.software.proprietary.security.model.Authority;
import stirling.software.proprietary.security.model.User;
@Service
@RequiredArgsConstructor

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.security.database;
package stirling.software.proprietary.security.service;
import java.io.IOException;
import java.nio.file.DirectoryStream;
@ -18,24 +18,19 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.init.CannotReadScriptException;
import org.springframework.jdbc.datasource.init.ScriptException;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.model.exception.BackupNotFoundException;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.FileInfo;
import stirling.software.proprietary.security.model.exception.BackupNotFoundException;
@Slf4j
@Service
public class DatabaseService implements DatabaseInterface {
public class DatabaseService implements DatabaseServiceInterface {
public static final String BACKUP_PREFIX = "backup_";
public static final String SQL_SUFFIX = ".sql";
@ -240,27 +235,27 @@ public class DatabaseService implements DatabaseInterface {
private boolean isH2Database() {
boolean isTypeH2 =
datasourceProps.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name());
datasourceProps.getType().equalsIgnoreCase(ApplicationProperties.Driver.H2.name());
boolean isDBUrlH2 =
datasourceProps.getCustomDatabaseUrl().contains("h2")
|| datasourceProps.getCustomDatabaseUrl().contains("H2");
datasourceProps.getCustomDatabaseUrl().contains("h2")
|| datasourceProps.getCustomDatabaseUrl().contains("H2");
boolean isCustomDatabase = datasourceProps.isEnableCustomDatabase();
if (isCustomDatabase) {
if (isTypeH2 && !isDBUrlH2) {
log.warn(
"Datasource type is H2, but the URL does not contain 'h2'. "
+ "Please check your configuration.");
"Datasource type is H2, but the URL does not contain 'h2'. "
+ "Please check your configuration.");
throw new IllegalStateException(
"Datasource type is H2, but the URL does not contain 'h2'. Please check"
+ " your configuration.");
"Datasource type is H2, but the URL does not contain 'h2'. Please check"
+ " your configuration.");
} else if (!isTypeH2 && isDBUrlH2) {
log.warn(
"Datasource URL contains 'h2', but the type is not H2. "
+ "Please check your configuration.");
"Datasource URL contains 'h2', but the type is not H2. "
+ "Please check your configuration.");
throw new IllegalStateException(
"Datasource URL contains 'h2', but the type is not H2. Please check your"
+ " configuration.");
"Datasource URL contains 'h2', but the type is not H2. Please check your"
+ " configuration.");
}
}
boolean isH2 = isTypeH2 && isDBUrlH2;

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.interfaces;
package stirling.software.proprietary.security.service;
import java.sql.SQLException;
import java.util.List;
@ -6,7 +6,7 @@ import java.util.List;
import stirling.software.common.model.FileInfo;
import stirling.software.common.model.exception.UnsupportedProviderException;
public interface DatabaseInterface {
public interface DatabaseServiceInterface {
void exportDatabase() throws SQLException, UnsupportedProviderException;
void importDatabase();

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.security.mail;
package stirling.software.proprietary.security.service;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.mail.javamail.JavaMailSender;
@ -12,8 +12,8 @@ import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.model.api.Email;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.proprietary.security.model.api.Email;
/**
* Service class responsible for sending emails, including those with attachments. It uses

View File

@ -1,17 +1,13 @@
package stirling.software.SPDF.config.security;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Service;
package stirling.software.proprietary.security.service;
import jakarta.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.model.AttemptCounter;
import org.springframework.stereotype.Service;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.proprietary.security.model.AttemptCounter;
@Service
@Slf4j

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.security;
package stirling.software.proprietary.security.service;
import java.io.IOException;
import java.sql.SQLException;
@ -9,7 +9,8 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -24,22 +25,17 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
import stirling.software.SPDF.model.AuthenticationType;
import stirling.software.SPDF.model.Authority;
import stirling.software.SPDF.model.Role;
import stirling.software.SPDF.model.User;
import stirling.software.SPDF.repository.AuthorityRepository;
import stirling.software.SPDF.repository.UserRepository;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException;
import stirling.software.common.service.UserServiceInterface;
import stirling.software.common.model.enumeration.Role;
import stirling.software.proprietary.security.database.repository.AuthorityRepository;
import stirling.software.proprietary.security.database.repository.UserRepository;
import stirling.software.proprietary.security.model.AuthenticationType;
import stirling.software.proprietary.security.model.Authority;
import stirling.software.proprietary.security.model.User;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.proprietary.security.session.SessionPersistentRegistry;
@Service
@Slf4j
@ -56,7 +52,7 @@ public class UserService implements UserServiceInterface {
private final SessionPersistentRegistry sessionRegistry;
private final DatabaseInterface databaseService;
private final DatabaseServiceInterface databaseService;
private final ApplicationProperties.Security.OAUTH2 oAuth2;
@ -306,7 +302,6 @@ public class UserService implements UserServiceInterface {
public void changeUsername(User user, String newUsername)
throws IllegalArgumentException,
IOException,
SQLException,
UnsupportedProviderException {
if (!isUsernameValid(newUsername)) {
@ -418,7 +413,7 @@ public class UserService implements UserServiceInterface {
if (principal instanceof UserDetails detailsUser) {
return detailsUser.getUsername();
} else if (principal instanceof stirling.software.SPDF.model.User domainUser) {
} else if (principal instanceof User domainUser) {
return domainUser.getUsername();
} else if (principal instanceof OAuth2User oAuth2User) {
return oAuth2User.getAttribute(oAuth2.getUseAsUsername());

View File

@ -1,11 +1,9 @@
package stirling.software.SPDF.config.security.session;
import org.springframework.stereotype.Component;
package stirling.software.proprietary.security.session;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j

View File

@ -1,21 +1,23 @@
package stirling.software.SPDF.config.security.session;
package stirling.software.proprietary.security.session;
import jakarta.transaction.Transactional;
import java.time.Duration;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal;
import stirling.software.SPDF.model.SessionEntity;
import stirling.software.proprietary.security.database.repository.SessionRepository;
import stirling.software.proprietary.security.model.SessionEntity;
import stirling.software.proprietary.security.saml2.CustomSaml2AuthenticatedPrincipal;
@Component
@RequiredArgsConstructor

View File

@ -1,8 +1,9 @@
package stirling.software.SPDF.config.security.session;
package stirling.software.proprietary.security.session;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.session.SessionRegistryImpl;
import stirling.software.proprietary.security.database.repository.SessionRepository;
@Configuration
public class SessionRegistryConfig {
@ -13,8 +14,7 @@ public class SessionRegistryConfig {
}
@Bean
public SessionPersistentRegistry sessionPersistentRegistry(
SessionRepository sessionRepository) {
public SessionPersistentRegistry sessionPersistentRegistry(SessionRepository sessionRepository) {
return new SessionPersistentRegistry(sessionRepository);
}
}

View File

@ -1,16 +1,14 @@
package stirling.software.SPDF.config.security.session;
package stirling.software.proprietary.security.session;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class SessionScheduled {

View File

@ -1,22 +1,17 @@
package stirling.software.SPDF.config.security;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
package stirling.software.proprietary.security;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import stirling.software.common.model.ApplicationProperties;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class CustomLogoutSuccessHandlerTest {

View File

@ -1,11 +1,6 @@
package stirling.software.SPDF.config.security.database;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
package stirling.software.proprietary.security.configuration;
import javax.sql.DataSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -13,9 +8,10 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.exception.UnsupportedProviderException;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class DatabaseConfigTest {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.controller.api;
package stirling.software.proprietary.security.controller.api;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
@ -23,8 +23,8 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import jakarta.mail.MessagingException;
import stirling.software.SPDF.config.security.mail.EmailService;
import stirling.software.SPDF.model.api.Email;
import stirling.software.proprietary.security.model.api.Email;
import stirling.software.proprietary.security.service.EmailService;
@ExtendWith(MockitoExtension.class)
class EmailControllerTest {

View File

@ -1,9 +1,9 @@
package stirling.software.SPDF.config.security.mail;
package stirling.software.proprietary.security.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.*;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@ -15,8 +15,11 @@ import org.springframework.web.multipart.MultipartFile;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import stirling.software.SPDF.model.api.Email;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.proprietary.security.model.api.Email;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class EmailServiceTest {

View File

@ -1,4 +1,4 @@
package stirling.software.SPDF.config.security.mail;
package stirling.software.proprietary.security.service;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -14,6 +14,7 @@ import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.proprietary.security.configuration.MailConfig;
class MailConfigTest {

View File

@ -182,7 +182,8 @@ def compare_files(
sort_ignore_translation[language]["ignore"].remove(
default_key.strip()
)
except ValueError:
except ValueError as e:
print(f"Error processing line {line_num} in {file_path}: {e}")
print(f"{line_default}|{line_file}")
exit(1)
except IndexError:

View File

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

View File

@ -1,34 +1,190 @@
[ar_AR]
ignore = [
'lang.div',
'lang.dzo',
'lang.que',
'language.direction',
]
[az_AZ]
ignore = [
'lang.afr',
'lang.bre',
'lang.div',
'lang.epo',
'lang.guj',
'lang.hin',
'lang.kan',
'lang.mal',
'lang.mar',
'lang.mlt',
'lang.mri',
'lang.msa',
'lang.nep',
'lang.ori',
'lang.pan',
'lang.san',
'lang.sin',
'lang.slk',
'lang.snd',
'lang.sun',
'lang.tam',
'lang.tat',
'lang.urd',
'lang.yor',
'language.direction',
]
[bg_BG]
ignore = [
'lang.div',
'lang.dzo',
'lang.iku',
'lang.que',
'language.direction',
]
[bo_CN]
ignore = [
'language.direction',
]
[ca_CA]
ignore = [
'PDFToText.tags',
'adminUserSettings.admin',
'lang.amh',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.fao',
'lang.fry',
'lang.guj',
'lang.hin',
'lang.iku',
'lang.kan',
'lang.kaz',
'lang.lao',
'lang.mar',
'lang.mri',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.snd',
'lang.swa',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tgl',
'lang.tir',
'lang.uzb',
'lang.uzb_cyrl',
'language.direction',
'watermark.type.1',
]
[cs_CZ]
ignore = [
'lang.amh',
'lang.asm',
'lang.bod',
'lang.bos',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.frk',
'lang.gla',
'lang.guj',
'lang.iku',
'lang.jav',
'lang.kan',
'lang.kat',
'lang.khm',
'lang.kir',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.msa',
'lang.nor',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.san',
'lang.sin',
'lang.snd',
'lang.sun',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgl',
'lang.tha',
'lang.tir',
'lang.uig',
'lang.urd',
'lang.uzb',
'lang.uzb_cyrl',
'lang.yor',
'language.direction',
'text',
]
[da_DK]
ignore = [
'lang.afr',
'lang.amh',
'lang.ben',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.frk',
'lang.guj',
'lang.hin',
'lang.iku',
'lang.jav',
'lang.kan',
'lang.khm',
'lang.lao',
'lang.lat',
'lang.ltz',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.msa',
'lang.nep',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.san',
'lang.sin',
'lang.slk_frak',
'lang.snd',
'lang.sun',
'lang.swa',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tgl',
'lang.tha',
'lang.tir',
'lang.ton',
'lang.uig',
'lang.urd',
'lang.uzb',
'lang.yor',
'language.direction',
]
@ -41,8 +197,36 @@ ignore = [
'addPageNumbers.selectText.3',
'alphabet',
'certSign.name',
'cookieBanner.popUp.acceptAllBtn',
'endpointStatistics.top10',
'endpointStatistics.top20',
'fileChooser.dragAndDrop',
'home.pipeline.title',
'lang.afr',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.guj',
'lang.hin',
'lang.iku',
'lang.kan',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.nep',
'lang.ori',
'lang.pan',
'lang.que',
'lang.san',
'lang.snd',
'lang.tam',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.urd',
'lang.yor',
'language.direction',
'legal.impressum',
'licenses.version',
@ -56,13 +240,19 @@ ignore = [
'validateSignature.cert.version',
'validateSignature.status',
'watermark.type.1',
'endpointStatistics.top10',
'endpointStatistics.top20',
'cookieBanner.popUp.acceptAllBtn',
]
[el_GR]
ignore = [
'lang.ceb',
'lang.dzo',
'lang.iku',
'lang.ori',
'lang.pan',
'lang.que',
'lang.sin',
'lang.uig',
'lang.uzb_cyrl',
'language.direction',
]
@ -70,6 +260,31 @@ ignore = [
ignore = [
'adminUserSettings.roles',
'error',
'lang.asm',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.fil',
'lang.frm',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.san',
'lang.snd',
'lang.sun',
'lang.tam',
'lang.tel',
'lang.tir',
'lang.urd',
'lang.uzb',
'lang.yor',
'language.direction',
'no',
'showJS.tags',
@ -77,6 +292,23 @@ ignore = [
[eu_ES]
ignore = [
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.mal',
'lang.pan',
'lang.que',
'lang.san',
'lang.slv',
'lang.snd',
'lang.sqi',
'lang.tat',
'lang.tir',
'lang.yor',
'language.direction',
]
@ -96,6 +328,31 @@ ignore = [
'alphabet',
'compare.document.1',
'compare.document.2',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.eus',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.kaz',
'lang.khm',
'lang.lao',
'lang.ltz',
'lang.mal',
'lang.mar',
'lang.oci',
'lang.ori',
'lang.que',
'lang.san',
'lang.snd',
'lang.swa',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.yor',
'language.direction',
'licenses.license',
'licenses.module',
@ -108,6 +365,24 @@ ignore = [
[ga_IE]
ignore = [
'lang.ceb',
'lang.cos',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.guj',
'lang.hat',
'lang.iku',
'lang.lao',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.sin',
'lang.snd',
'lang.sun',
'lang.tgk',
'lang.tir',
'lang.uig',
'language.direction',
]
@ -120,22 +395,126 @@ ignore = [
ignore = [
'PDFToBook.selectText.1',
'home.pipeline.title',
'lang.bod',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.dzo',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.lao',
'lang.mri',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.san',
'lang.snd',
'lang.tam',
'lang.tel',
'lang.tgl',
'lang.tir',
'language.direction',
'showJS.tags',
]
[hu_HU]
ignore = [
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.fao',
'lang.iku',
'lang.kan',
'lang.lao',
'lang.mar',
'lang.mri',
'lang.ori',
'lang.que',
'lang.tel',
'lang.tgl',
'language.direction',
]
[id_ID]
ignore = [
'lang.aze',
'lang.aze_cyrl',
'lang.bre',
'lang.cat',
'lang.ceb',
'lang.chr',
'lang.cym',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.eus',
'lang.fao',
'lang.frk',
'lang.guj',
'lang.hin',
'lang.iku',
'lang.kan',
'lang.kaz',
'lang.kir',
'lang.lao',
'lang.lat',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.slk_frak',
'lang.snd',
'lang.sun',
'lang.swa',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tgl',
'lang.tha',
'lang.tir',
'lang.uig',
'lang.urd',
'lang.uzb',
'lang.uzb_cyrl',
'lang.yor',
'language.direction',
]
[it_IT]
ignore = [
'lang.asm',
'lang.aze',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.fao',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.snd',
'lang.swa',
'lang.tam',
'lang.tel',
'lang.tgl',
'lang.urd',
'lang.yor',
'language.direction',
'no',
'password',
@ -148,11 +527,21 @@ ignore = [
[ja_JP]
ignore = [
'lang.jav',
'language.direction',
]
[ko_KR]
ignore = [
'lang.fao',
'lang.pus',
'lang.sun',
'language.direction',
]
[ml_IN]
ignore = [
'lang.iku',
'language.direction',
]
@ -160,6 +549,37 @@ ignore = [
ignore = [
'compare.document.1',
'compare.document.2',
'lang.afr',
'lang.asm',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.dzo',
'lang.epo',
'lang.fao',
'lang.guj',
'lang.hin',
'lang.iku',
'lang.kan',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.sin',
'lang.snd',
'lang.sun',
'lang.swa',
'lang.tam',
'lang.tel',
'lang.tgl',
'lang.ton',
'lang.urd',
'lang.yor',
'language.direction',
'navbar.allTools',
'sponsor',
@ -170,6 +590,49 @@ ignore = [
'PDFToBook.selectText.1',
'adminUserSettings.admin',
'info',
'lang.afr',
'lang.amh',
'lang.ben',
'lang.bos',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.dan_frak',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.guj',
'lang.hin',
'lang.iku',
'lang.kan',
'lang.khm',
'lang.lao',
'lang.lat',
'lang.ltz',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.msa',
'lang.nep',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.que',
'lang.san',
'lang.slk_frak',
'lang.snd',
'lang.swa',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tgl',
'lang.tha',
'lang.tir',
'lang.ton',
'lang.uig',
'lang.urd',
'lang.yor',
'language.direction',
'oops',
'sponsor',
@ -178,27 +641,148 @@ ignore = [
[pl_PL]
ignore = [
'PDFToBook.selectText.1',
'lang.afr',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.cos',
'lang.div',
'lang.dzo',
'lang.fao',
'lang.frk',
'lang.guj',
'lang.hat',
'lang.iku',
'lang.kan',
'lang.khm',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.nep',
'lang.oci',
'lang.ori',
'lang.pus',
'lang.que',
'lang.snd',
'lang.sun',
'lang.swa',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.uig',
'lang.urd',
'language.direction',
]
[pt_BR]
ignore = [
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.fao',
'lang.fil',
'lang.frk',
'lang.fry',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.kir',
'lang.mar',
'lang.ori',
'lang.pan',
'lang.que',
'lang.snd',
'lang.tat',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.uig',
'lang.uzb',
'lang.yid',
'language.direction',
'pipelineOptions.pipelineHeader',
]
[pt_PT]
ignore = [
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.fao',
'lang.fil',
'lang.frk',
'lang.fry',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.kir',
'lang.mar',
'lang.ori',
'lang.pan',
'lang.que',
'lang.snd',
'lang.tat',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.uig',
'lang.uzb',
'lang.yid',
'language.direction',
]
[ro_RO]
ignore = [
'lang.amh',
'lang.asm',
'lang.bod',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.cos',
'lang.deu_frak',
'lang.div',
'lang.dzo',
'lang.est',
'lang.fao',
'lang.glg',
'lang.guj',
'lang.iku',
'lang.jav',
'lang.kan',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.nep',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.pus',
'lang.slk_frak',
'lang.snd',
'lang.sun',
'lang.swa',
'lang.tam',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.urd',
'lang.yor',
'language.direction',
]
[ru_RU]
ignore = [
'lang.iku',
'lang.pus',
'language.direction',
]
@ -207,6 +791,25 @@ ignore = [
'adminUserSettings.admin',
'home.multiTool.title',
'info',
'lang.ceb',
'lang.chr',
'lang.dzo',
'lang.epo',
'lang.iku',
'lang.kaz',
'lang.mar',
'lang.ori',
'lang.pan',
'lang.que',
'lang.san',
'lang.sin',
'lang.snd',
'lang.tat',
'lang.tel',
'lang.tgl',
'lang.tir',
'lang.urd',
'lang.uzb',
'language.direction',
'navbar.sections.security',
'text',
@ -215,6 +818,37 @@ ignore = [
[sl_SI]
ignore = [
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.eus',
'lang.fao',
'lang.frk',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.lao',
'lang.mar',
'lang.mri',
'lang.oci',
'lang.ori',
'lang.pan',
'lang.que',
'lang.slk',
'lang.snd',
'lang.sun',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tgl',
'lang.tir',
'lang.urd',
'lang.uzb',
'lang.yor',
'language.direction',
]
@ -227,11 +861,43 @@ ignore = [
[sv_SE]
ignore = [
'lang.ben',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.dzo',
'lang.epo',
'lang.guj',
'lang.hin',
'lang.kan',
'lang.lao',
'lang.lat',
'lang.mal',
'lang.mri',
'lang.ori',
'lang.pan',
'lang.que',
'lang.san',
'lang.slk_frak',
'lang.snd',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tir',
'lang.urd',
'lang.yor',
'language.direction',
]
[th_TH]
ignore = [
'lang.dzo',
'lang.kir',
'lang.pan',
'lang.sin',
'lang.slk_frak',
'lang.tir',
'lang.uzb_cyrl',
'language.direction',
'pipelineOptions.pipelineHeader',
'showJS.tags',
@ -239,33 +905,111 @@ ignore = [
[tr_TR]
ignore = [
'lang.afr',
'lang.bre',
'lang.ceb',
'lang.chr',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.fao',
'lang.guj',
'lang.kan',
'lang.lao',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.msa',
'lang.ori',
'lang.pus',
'lang.que',
'lang.sin',
'lang.slk',
'lang.slk_frak',
'lang.snd',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tgl',
'lang.tir',
'lang.urd',
'lang.yor',
'language.direction',
]
[uk_UA]
ignore = [
'lang.iku',
'language.direction',
]
[vi_VN]
ignore = [
'lang.amh',
'lang.asm',
'lang.aze',
'lang.aze_cyrl',
'lang.bos',
'lang.bre',
'lang.cat',
'lang.ceb',
'lang.chr',
'lang.cos',
'lang.div',
'lang.dzo',
'lang.epo',
'lang.eus',
'lang.fao',
'lang.glg',
'lang.guj',
'lang.iku',
'lang.kan',
'lang.kaz',
'lang.kir',
'lang.lat',
'lang.ltz',
'lang.mal',
'lang.mar',
'lang.mri',
'lang.msa',
'lang.ori',
'lang.pus',
'lang.que',
'lang.sin',
'lang.slk',
'lang.slk_frak',
'lang.snd',
'lang.swa',
'lang.syr',
'lang.tam',
'lang.tat',
'lang.tel',
'lang.tgk',
'lang.tir',
'lang.uig',
'lang.uzb',
'lang.uzb_cyrl',
'lang.yid',
'lang.yor',
'language.direction',
'pipeline.title',
'pipelineOptions.pipelineHeader',
'showJS.tags',
]
[zh_BO]
ignore = [
'language.direction',
]
[zh_CN]
ignore = [
'lang.dzo',
'lang.iku',
'lang.que',
'language.direction',
]
[zh_TW]
ignore = [
'lang.dzo',
'lang.iku',
'lang.que',
'language.direction',
]

View File

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

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