From 68ed54e398b3f116c7b824c1f0bb86b558376e89 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Sun, 21 Dec 2025 10:40:32 +0000 Subject: [PATCH] V1 merge (#5193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes --- ## 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/devGuide/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/devGuide/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/devGuide/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/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Signed-off-by: dependabot[bot] Signed-off-by: Balázs Szücs Signed-off-by: stirlingbot[bot] Co-authored-by: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com> Co-authored-by: Connor Yoh Co-authored-by: OUNZAR Aymane Co-authored-by: YAOU Reda Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com> Co-authored-by: Balázs Szücs <127139797+balazs-szucs@users.noreply.github.com> Co-authored-by: Ludy Co-authored-by: tkymmm <136296842+tkymmm@users.noreply.github.com> Co-authored-by: Peter Dave Hello Co-authored-by: albanobattistella <34811668+albanobattistella@users.noreply.github.com> Co-authored-by: PingLin8888 <88387490+PingLin8888@users.noreply.github.com> Co-authored-by: FdaSilvaYY Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: OteJlo <106060728+OteJlo@users.noreply.github.com> Co-authored-by: Angel <41905618+TheShadowAngel@users.noreply.github.com> Co-authored-by: Ricardo Catarino Co-authored-by: Luis Antonio Argüelles González Co-authored-by: Dawid Urbański <31166488+urbaned121@users.noreply.github.com> Co-authored-by: Stephan Paternotte Co-authored-by: Leonardo Santos Paulucio Co-authored-by: hamza khalem <72972114+hamzakhalem@users.noreply.github.com> Co-authored-by: IT Creativity + Art Team Co-authored-by: Reece Browne <74901996+reecebrowne@users.noreply.github.com> Co-authored-by: James Brunton Co-authored-by: Victor Villarreal <133383186+vvillarreal-cfee@users.noreply.github.com> --- .github/config/.files.yaml | 30 +- .github/config/repo_devs.json | 5 + .github/labels.yml | 3 + .github/pull_request_template.md | 4 + .github/release.yml | 4 + .github/scripts/requirements_dev.in | 1 + .github/scripts/requirements_dev.txt | 758 ++++---- .github/scripts/requirements_pre_commit.txt | 18 +- .../workflows/PR-Demo-Comment-with-react.yml | 156 +- .github/workflows/PR-Demo-cleanup.yml | 4 +- .github/workflows/ai_pr_title_review.yml | 4 +- .github/workflows/auto-labelerV2.yml | 7 +- .github/workflows/check_toml.yml | 4 +- .github/workflows/dependency-review.yml | 6 +- .github/workflows/licenses-update.yml | 8 +- .github/workflows/manage-label.yml | 4 +- .github/workflows/multiOSReleases.yml | 30 +- .github/workflows/pre_commit.yml | 6 +- .github/workflows/push-docker-v2.yml | 14 +- .github/workflows/push-docker.yml | 14 +- .github/workflows/releaseArtifacts.yml | 14 +- .github/workflows/scorecards.yml | 8 +- .github/workflows/sonarqube.yml | 76 - .github/workflows/stale.yml | 2 +- .github/workflows/swagger.yml | 4 +- .github/workflows/sync_files_v2.yml | 6 +- .github/workflows/testdriver.yml | 14 +- .pre-commit-config.yaml | 4 +- app/common/build.gradle | 6 +- .../SPDF/config/EndpointConfiguration.java | 9 +- .../software/common/aop/AutoJobAspect.java | 17 +- .../common/configuration/AppConfig.java | 17 +- .../configuration/InstallationPathConfig.java | 3 +- .../configuration/RuntimePathConfig.java | 42 +- .../common/model/ApplicationProperties.java | 61 +- .../software/common/model/FileInfo.java | 6 +- .../service/CustomPDFDocumentFactory.java | 10 +- .../common/service/JobExecutorService.java | 16 + .../common/service/PostHogService.java | 10 +- .../common/service/ResourceMonitor.java | 5 +- .../common/service/SsrfProtectionService.java | 13 +- .../software/common/service/TaskManager.java | 15 +- .../software/common/util/CbrUtils.java | 41 +- .../software/common/util/CbzUtils.java | 23 +- .../common/util/CheckProgramInstall.java | 23 + .../software/common/util/ChecksumUtils.java | 34 +- .../common/util/CustomHtmlSanitizer.java | 3 +- .../software/common/util/EmlParser.java | 29 +- .../common/util/EmlProcessingUtils.java | 261 +-- .../software/common/util/ExceptionUtils.java | 1395 +++++++++++++-- .../software/common/util/FileToPdf.java | 74 +- .../common/util/GeneralFormCopyUtils.java} | 13 +- .../util/GeneralFormFieldTypeSupport.java | 165 ++ .../software/common/util/GeneralUtils.java | 273 ++- .../common/util/ImageProcessingUtils.java | 8 +- .../software/common/util/PDFToFile.java | 105 +- .../common/util/PdfAttachmentHandler.java | 4 +- .../software/common/util/PdfToCbrUtils.java | 47 +- .../software/common/util/PdfToCbzUtils.java | 36 +- .../software/common/util/PdfUtils.java | 140 +- .../software/common/util/ProcessExecutor.java | 13 +- .../common/util/RegexPatternUtils.java | 15 + .../software/common/util/TempFileManager.java | 12 +- .../software/common/util/ValidationUtil.java | 14 - .../util/misc/InvertFullColorStrategy.java | 16 +- .../AutoJobPostMappingIntegrationTest.java | 14 +- .../interfaces/ShowAdminInterfaceTest.java | 17 + ...opertiesDynamicYamlPropertySourceTest.java | 18 +- .../ApplicationPropertiesSaml2HttpTest.java | 4 +- .../software/common/model/FileInfoTest.java | 207 ++- .../UnsupportedClaimExceptionTest.java | 34 + .../service/CustomPDFDocumentFactoryTest.java | 111 +- .../common/service/FileStorageTest.java | 12 +- .../service/JobExecutorServiceTest.java | 21 +- .../common/service/ResourceMonitorTest.java | 23 +- .../common/service/TaskManagerTest.java | 29 +- .../service/TempFileCleanupServiceTest.java | 90 +- .../common/util/CheckProgramInstallTest.java | 65 +- .../common/util/ChecksumUtilsTest.java | 2 +- .../common/util/CustomHtmlSanitizerTest.java | 201 ++- .../software/common/util/EmlToPdfTest.java | 42 +- .../software/common/util/ErrorUtilsTest.java | 3 +- .../common/util/ExceptionUtilsTest.java | 354 ++++ .../software/common/util/FileMonitorTest.java | 47 +- .../software/common/util/FileToPdfTest.java | 6 +- .../util/GeneralUtilsAdditionalTest.java | 15 + .../common/util/ImageProcessingUtilsTest.java | 28 +- .../software/common/util/PDFToFileTest.java | 142 +- .../software/common/util/PdfUtilsTest.java | 663 ++++++- .../common/util/ProcessExecutorTest.java | 9 +- .../common/util/PropertyConfigsTest.java | 5 +- .../common/util/RegexPatternUtilsTest.java | 10 +- .../common/util/RequestUriUtilsTest.java | 3 +- .../common/util/SpringContextHolderTest.java | 9 +- .../common/util/TempDirectoryTest.java | 96 + .../software/common/util/UIScalingTest.java | 4 +- .../software/common/util/UrlUtilsTest.java | 5 +- .../common/util/WebResponseUtilsTest.java | 4 +- .../misc/CustomColorReplaceStrategyTest.java | 5 +- .../HighContrastColorReplaceDeciderTest.java | 3 +- .../misc/InvertFullColorStrategyTest.java | 31 +- .../util/misc/PdfTextStripperCustomTest.java | 10 +- .../ReplaceAndInvertColorStrategyTest.java | 3 +- .../StringToArrayListPropertyEditorTest.java | 15 +- .../StringToMapPropertyEditorTest.java | 13 +- app/core/build.gradle | 6 +- .../ReplaceAndInvertColorFactory.java | 4 + .../SPDF/config/ExternalAppDepConfig.java | 462 +++-- .../software/SPDF/config/OpenApiConfig.java | 2 +- .../SPDF/controller/api/CropController.java | 319 +++- .../api/EditTableOfContentsController.java | 49 +- .../SPDF/controller/api/MergeController.java | 18 +- .../api/MultiPageLayoutController.java | 44 +- .../controller/api/PdfOverlayController.java | 23 +- .../api/RearrangePagesPDFController.java | 23 +- .../controller/api/ScalePagesController.java | 185 +- .../controller/api/SettingsController.java | 12 +- .../controller/api/SplitPDFController.java | 39 +- .../api/SplitPdfByChaptersController.java | 3 +- .../api/SplitPdfBySectionsController.java | 161 +- .../ConvertEbookToPDFController.java | 208 +++ .../api/converters/ConvertEmlToPDF.java | 9 +- .../converters/ConvertImgPDFController.java | 61 +- .../converters/ConvertOfficeController.java | 19 +- .../ConvertPDFToEpubController.java | 204 +++ .../api/converters/ConvertPDFToHtml.java | 18 +- .../api/converters/ConvertPDFToOffice.java | 36 +- .../api/converters/ConvertPDFToPDFA.java | 1551 ++++++++++++++--- .../ConvertPdfToVideoController.java | 293 ++++ .../api/converters/ConvertWebsiteToPDF.java | 143 +- .../api/converters/ExtractCSVController.java | 3 +- .../converters/PdfVectorExportController.java | 252 +++ .../api/filters/FilterController.java | 238 +-- .../api/misc/AttachmentController.java | 34 + .../api/misc/AutoSplitPdfController.java | 14 +- .../api/misc/BlankPageController.java | 27 +- .../api/misc/CompressController.java | 1104 ++++++++---- .../controller/api/misc/ConfigController.java | 4 +- .../api/misc/ExtractImageScansController.java | 17 +- .../api/misc/FlattenController.java | 68 +- .../controller/api/misc/OCRController.java | 68 +- .../api/misc/PrintFileController.java | 21 +- .../controller/api/misc/RepairController.java | 5 +- .../api/misc/ScannerEffectController.java | 1179 ++++++++----- .../controller/api/misc/StampController.java | 111 +- .../pipeline/PipelineDirectoryProcessor.java | 9 +- .../api/pipeline/PipelineProcessor.java | 32 +- .../controller/api/security/GetInfoOnPDF.java | 1188 ++++++++----- .../api/security/PasswordController.java | 12 +- .../api/security/RedactController.java | 9 +- .../web/ConverterWebController.java | 107 +- .../controller/web/HomeWebController.java | 4 +- .../controller/web/MetricsController.java | 6 +- .../controller/web/OtherWebController.java | 14 +- .../controller/web/UploadLimitService.java | 2 +- .../exception/GlobalExceptionHandler.java | 1278 ++++++++++++++ .../software/SPDF/model/SplitTypes.java | 9 + .../model/api/SplitPdfByChaptersRequest.java | 6 +- .../model/api/SplitPdfBySectionsRequest.java | 20 +- .../converters/ConvertEbookToPdfRequest.java | 53 + .../converters/ConvertPdfToEpubRequest.java | 58 + .../api/converters/PdfToPdfARequest.java | 7 +- .../api/converters/PdfToVideoRequest.java | 53 + .../converters/PdfVectorExportRequest.java | 29 + .../SPDF/model/api/general/CropPdfForm.java | 11 +- .../SPDF/model/api/misc/AddStampRequest.java | 6 +- .../api/misc/ExtractAttachmentsRequest.java | 10 + .../SPDF/model/api/misc/FlattenRequest.java | 6 + .../model/api/misc/ScannerEffectRequest.java | 36 +- .../api/security/AddWatermarkRequest.java | 2 +- .../software/SPDF/pdf/TextFinder.java | 5 +- .../software/SPDF/service/ApiDocService.java | 3 +- .../SPDF/service/AttachmentService.java | 238 +++ .../service/AttachmentServiceInterface.java | 3 + .../service/MetricsAggregatorService.java | 6 +- .../SPDF/utils/text/TextEncodingHelper.java | 30 +- .../src/main/resources/application.properties | 4 + .../src/main/resources/settings.yml.template | 12 +- .../resources/static/3rdPartyLicenses.json | 274 +-- .../resources/static/css/imageHighlighter.css | 2 +- .../static/css/split-pdf-by-sections.css | 3 + .../main/resources/static/js/DecryptFiles.js | 279 ++- .../resources/static/js/compare/pdfWorker.js | 230 ++- .../main/resources/static/js/downloader.js | 350 +++- .../main/resources/static/js/errorBanner.js | 2 +- .../src/main/resources/static/js/fileInput.js | 66 + .../src/main/resources/static/js/homecard.js | 10 +- .../src/main/resources/static/js/merge.js | 54 +- .../static/js/multitool/ImageHighlighter.js | 19 - .../static/js/multitool/PdfActionsManager.js | 26 +- .../static/js/multitool/PdfContainer.js | 239 ++- .../static/js/multitool/commands/add-page.js | 81 +- .../static/js/multitool/commands/command.js | 60 + .../multitool/commands/commands-sequence.js | 16 +- .../js/multitool/commands/delete-page.js | 57 +- .../js/multitool/commands/duplicate-page.js | 63 + .../static/js/multitool/commands/move-page.js | 26 +- .../js/multitool/commands/page-break.js | 90 +- .../static/js/multitool/commands/remove.js | 51 +- .../static/js/multitool/commands/rotate.js | 45 +- .../static/js/multitool/commands/select.js | 38 +- .../static/js/multitool/commands/split.js | 78 +- .../src/main/resources/static/js/navbar.js | 2 +- .../resources/static/js/pages/add-image.js | 13 +- .../static/js/pages/adjust-contrast.js | 13 +- .../static/js/pages/change-metadata.js | 15 +- .../main/resources/static/js/pages/crop.js | 98 +- .../resources/static/js/pages/pdf-to-csv.js | 57 +- .../main/resources/static/js/pages/sign.js | 14 +- .../js/thirdParty/cookieconsent-config.js | 17 +- .../templates/convert/ebook-to-pdf.html | 82 + .../templates/convert/pdf-to-epub.html | 87 + .../templates/convert/pdf-to-pdfa.html | 14 +- .../templates/convert/pdf-to-vector.html | 46 + .../templates/convert/pdf-to-video.html | 84 + .../templates/convert/vector-to-pdf.html | 41 + .../src/main/resources/templates/crop.html | 6 + .../resources/templates/fragments/common.html | 71 +- .../templates/fragments/errorBanner.html | 191 +- .../fragments/errorBannerPerPage.html | 2 +- .../templates/fragments/languages.html | 2 +- .../templates/fragments/navElements.html | 33 + .../resources/templates/fragments/navbar.html | 3 + .../main/resources/templates/home-legacy.html | 6 + .../main/resources/templates/merge-pdfs.html | 2 +- .../resources/templates/misc/compare.html | 314 ++-- .../templates/misc/compress-pdf.html | 6 + .../templates/misc/extract-attachments.html | 52 + .../resources/templates/misc/flatten.html | 15 +- .../main/resources/templates/multi-tool.html | 5 + .../resources/templates/pdf-organizer.html | 23 +- .../main/resources/templates/rotate-pdf.html | 24 +- .../templates/security/get-info-on-pdf.html | 244 ++- .../templates/split-pdf-by-sections.html | 37 + .../util/ConnectedInputStreamTest.java | 86 + .../ReplaceAndInvertColorFactoryTest.java | 93 + .../software/SPDF/SPDFApplicationTest.java | 25 + .../SPDF/config/ExternalAppDepConfigTest.java | 185 ++ .../AdditionalLanguageJsControllerTest.java | 59 + .../controller/api/CropControllerTest.java | 686 ++++++++ .../EditTableOfContentsControllerTest.java | 26 +- .../controller/api/MergeControllerTest.java | 8 +- .../api/RearrangePagesPDFControllerTest.java | 8 +- .../api/RotationControllerTest.java | 6 +- .../ConvertEbookToPDFControllerTest.java | 266 +++ .../ConvertPDFToEpubControllerTest.java | 328 ++++ .../api/converters/ConvertPDFToPDFATest.java | 571 ++++++ .../converters/ConvertWebsiteToPdfTest.java | 126 +- .../api/converters/PdfToCbzUtilsTest.java | 18 +- .../PdfVectorExportControllerTest.java | 146 ++ .../api/misc/AttachmentControllerTest.java | 1 - .../api/pipeline/PipelineProcessorTest.java | 22 +- .../api/security/GetInfoOnPDFTest.java | 843 +++++++++ .../api/security/RedactControllerTest.java | 669 ++++--- .../web/ConverterWebControllerTest.java | 231 +++ .../web/UploadLimitServiceTest.java | 55 +- .../software/SPDF/model/ApiEndpointTest.java | 104 ++ .../software/SPDF/model/SortTypesTest.java | 54 + .../SPDF/model/api/PDFWithPageNumsTest.java | 84 + .../converters/ConvertPDFToMarkdownTest.java | 109 ++ .../api/misc/ScannerEffectRequestTest.java | 130 ++ .../SPDF/pdf/FlexibleCSVWriterTest.java | 25 + .../software/SPDF/pdf/TextFinderTest.java | 23 +- .../SPDF/service/ApiDocServiceTest.java | 124 ++ .../SPDF/service/AttachmentServiceTest.java | 86 + .../service/LanguageServiceBasicTest.java | 52 +- .../SPDF/service/LanguageServiceTest.java | 56 +- .../service/MetricsAggregatorServiceTest.java | 75 + .../service/PdfImageRemovalServiceTest.java | 43 +- .../service/PdfMetadataServiceBasicTest.java | 6 +- .../ReplaceAndInvertColorServiceTest.java | 77 + app/proprietary/build.gradle | 4 +- .../proprietary/audit/AuditUtils.java | 9 +- .../api/ProprietaryUIDataController.java | 2 +- .../security/CustomLogoutSuccessHandler.java | 3 +- .../security/InitialSecuritySetup.java | 2 +- .../configuration/DatabaseConfig.java | 4 +- .../ee/KeygenLicenseVerifier.java | 9 +- .../DatabaseNotificationServiceInterface.java | 11 + .../service/DatabaseNotificationService.java | 75 + .../security/model/AttemptCounter.java | 3 +- .../proprietary/security/model/User.java | 3 +- .../security/oauth2/OAuth2Configuration.java | 6 +- .../service/AppUpdateAuthService.java | 2 +- .../service/CustomUserDetailsService.java | 4 +- .../security/service/DatabaseService.java | 64 +- .../security/service/EmailService.java | 36 + .../security/service/LoginAttemptService.java | 15 +- .../security/service/UserService.java | 9 +- .../software/proprietary/util/FormUtils.java | 6 +- .../software/proprietary/model/TeamTest.java | 74 + .../model/dto/TeamWithUserCountDTOTest.java | 58 + .../CustomLogoutSuccessHandlerTest.java | 3 - .../configuration/DatabaseConfigTest.java | 8 + .../ee/LicenseKeyCheckerTest.java | 4 +- .../security/database/H2SQLConditionTest.java | 87 + .../security/database/ScheduledTasksTest.java | 71 + .../JPATokenRepositoryImplTest.java | 141 ++ .../model/ApiKeyAuthenticationTokenTest.java | 84 + .../security/model/AttemptCounterTest.java | 285 +++ .../security/model/AuthorityTest.java | 96 + .../proprietary/security/model/UserTest.java | 152 ++ .../BackupNotFoundExceptionTest.java | 34 + .../NoProviderFoundExceptionTest.java | 33 + ...l2AuthenticationRequestRepositoryTest.java | 6 +- .../security/service/EmailServiceTest.java | 18 +- .../service/LoginAttemptServiceTest.java | 239 +++ .../security/service/MailConfigTest.java | 4 +- .../security/service/UserServiceTest.java | 23 +- .../proprietary/util/SecretMaskerTest.java | 176 ++ .../proprietary/web/AuditWebFilterTest.java | 317 ++++ .../web/CorrelationIdFilterTest.java | 188 ++ build.gradle | 29 +- devGuide/DeveloperGuide.md | 8 +- devTools/package-lock.json | 299 ++-- devTools/package.json | 6 +- docker/backend/Dockerfile | 210 ++- docker/backend/Dockerfile.fat | 225 ++- docker/backend/Dockerfile.ultra-lite | 29 +- docker/embedded/Dockerfile | 202 ++- docker/embedded/Dockerfile.fat | 207 ++- ...-compose-latest-fat-endpoints-disabled.yml | 36 + .../docker-compose-latest-fat-security.yml | 34 + .../docker-compose-latest-ultra-lite.yml | 29 + .../embedded/compose}/test_cicd.yml | 8 +- docs/counter_translation.md | 64 + frontend/src-tauri/tauri.conf.json | 2 +- .../testing/serverExperienceSimulations.ts | 2 +- .../testing/serverExperienceSimulations.ts | 2 +- scripts/counter_translation_v3.py | 385 +++- scripts/generate_requirements.bat | 5 + scripts/ignore_translation.toml | 105 +- scripts/init-without-ocr.sh | 203 ++- scripts/init.sh | 120 +- testing/allEndpointsRemovedSettings.yml | 85 +- testing/cucumber/features/examples.feature | 4 +- testing/cucumber/features/external.feature | 53 + .../features/steps/step_definitions.py | 16 +- testing/cucumber/requirements.txt | 427 ++--- testing/endpoints.txt | 1 + testing/test.sh | 491 ++++-- testing/webpage_urls.txt | 1 - testing/webpage_urls_full.txt | 4 +- 343 files changed, 25212 insertions(+), 6592 deletions(-) delete mode 100644 .github/workflows/sonarqube.yml rename app/{proprietary/src/main/java/stirling/software/proprietary/util/FormCopyUtils.java => common/src/main/java/stirling/software/common/util/GeneralFormCopyUtils.java} (96%) create mode 100644 app/common/src/main/java/stirling/software/common/util/GeneralFormFieldTypeSupport.java delete mode 100644 app/common/src/main/java/stirling/software/common/util/ValidationUtil.java create mode 100644 app/common/src/test/java/stirling/software/common/configuration/interfaces/ShowAdminInterfaceTest.java create mode 100644 app/common/src/test/java/stirling/software/common/model/exception/UnsupportedClaimExceptionTest.java create mode 100644 app/common/src/test/java/stirling/software/common/util/ExceptionUtilsTest.java create mode 100644 app/common/src/test/java/stirling/software/common/util/TempDirectoryTest.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertEbookToPDFController.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToEpubController.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPdfToVideoController.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/controller/api/converters/PdfVectorExportController.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/exception/GlobalExceptionHandler.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/SplitTypes.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/api/converters/ConvertEbookToPdfRequest.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/api/converters/ConvertPdfToEpubRequest.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/api/converters/PdfToVideoRequest.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/api/converters/PdfVectorExportRequest.java create mode 100644 app/core/src/main/java/stirling/software/SPDF/model/api/misc/ExtractAttachmentsRequest.java create mode 100644 app/core/src/main/resources/static/js/multitool/commands/duplicate-page.js create mode 100644 app/core/src/main/resources/templates/convert/ebook-to-pdf.html create mode 100644 app/core/src/main/resources/templates/convert/pdf-to-epub.html create mode 100644 app/core/src/main/resources/templates/convert/pdf-to-vector.html create mode 100644 app/core/src/main/resources/templates/convert/pdf-to-video.html create mode 100644 app/core/src/main/resources/templates/convert/vector-to-pdf.html create mode 100644 app/core/src/main/resources/templates/misc/extract-attachments.html create mode 100644 app/core/src/test/java/org/apache/pdfbox/examples/util/ConnectedInputStreamTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/Factories/ReplaceAndInvertColorFactoryTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/config/ExternalAppDepConfigTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/AdditionalLanguageJsControllerTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/CropControllerTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertEbookToPDFControllerTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToEpubControllerTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFATest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/converters/PdfVectorExportControllerTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/api/security/GetInfoOnPDFTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/controller/web/ConverterWebControllerTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/model/ApiEndpointTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/model/SortTypesTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/model/api/PDFWithPageNumsTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/model/api/converters/ConvertPDFToMarkdownTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/model/api/misc/ScannerEffectRequestTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/pdf/FlexibleCSVWriterTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/service/ApiDocServiceTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/service/MetricsAggregatorServiceTest.java create mode 100644 app/core/src/test/java/stirling/software/SPDF/service/misc/ReplaceAndInvertColorServiceTest.java create mode 100644 app/proprietary/src/main/java/stirling/software/proprietary/security/database/DatabaseNotificationServiceInterface.java create mode 100644 app/proprietary/src/main/java/stirling/software/proprietary/security/database/service/DatabaseNotificationService.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/model/TeamTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/model/dto/TeamWithUserCountDTOTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/database/H2SQLConditionTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/database/ScheduledTasksTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/database/repository/JPATokenRepositoryImplTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/model/ApiKeyAuthenticationTokenTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/model/AttemptCounterTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/model/AuthorityTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/model/UserTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/model/exception/BackupNotFoundExceptionTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/model/exception/NoProviderFoundExceptionTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/security/service/LoginAttemptServiceTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/util/SecretMaskerTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/web/AuditWebFilterTest.java create mode 100644 app/proprietary/src/test/java/stirling/software/proprietary/web/CorrelationIdFilterTest.java create mode 100644 docker/embedded/compose/docker-compose-latest-fat-endpoints-disabled.yml create mode 100644 docker/embedded/compose/docker-compose-latest-fat-security.yml create mode 100644 docker/embedded/compose/docker-compose-latest-ultra-lite.yml rename {exampleYmlFiles => docker/embedded/compose}/test_cicd.yml (80%) create mode 100644 docs/counter_translation.md diff --git a/.github/config/.files.yaml b/.github/config/.files.yaml index 78f461683..f866770b5 100644 --- a/.github/config/.files.yaml +++ b/.github/config/.files.yaml @@ -6,22 +6,27 @@ app: &app - app/(common|core|proprietary)/src/main/java/** openapi: &openapi - - build.gradle - - app/(common|core|proprietary)/build.gradle - - app/(common|core|proprietary)/src/main/java/** + - *build + - *app -project: &project - - app/(common|core|proprietary)/src/(main|test)/java/** - - app/(common|core|proprietary)/build.gradle - - 'app/(common|core|proprietary)/src/(main|test)/resources/**/!(messages_*.properties|*.md)*' - - exampleYmlFiles/** - - gradle/** - - libs/** - - testing/** - - build.gradle +docker: &docker - Dockerfile - Dockerfile.fat - Dockerfile.ultra-lite + - ".github/workflows/build.yml" + - scripts/init.sh + - scripts/init-without-ocr.sh + - exampleYmlFiles/** + +project: &project + - app/(common|core|proprietary)/src/(main|test)/java/** + - *build + - "app/(common|core|proprietary)/src/(main|test)/resources/**/!(messages_*.properties|*.md)*" + - exampleYmlFiles/** + - gradle/** + - libs/** + - "testing/**/!(requirements*.txt|requirements*.in)*" + - *docker - gradle.properties - gradlew - gradlew.bat @@ -29,7 +34,6 @@ project: &project - settings.gradle - frontend/** - docker/** - - testing/** frontend: &frontend - frontend/** diff --git a/.github/config/repo_devs.json b/.github/config/repo_devs.json index 86d43fd98..963240260 100644 --- a/.github/config/repo_devs.json +++ b/.github/config/repo_devs.json @@ -1,4 +1,9 @@ { + "label_changer": [ + "Frooodle", + "Ludy87", + "balazs-szucs" + ], "repo_devs": [ "Frooodle", "sf298", diff --git a/.github/labels.yml b/.github/labels.yml index 842e3fb5c..a6c354e58 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -184,3 +184,6 @@ - name: "codex" color: "ededed" description: "chatgpt AI generated code" +- name: "break-change" + color: "FF0000" + description: "This PR introduces a breaking API change." diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b909f28e8..d1287c011 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -27,6 +27,10 @@ Closes #(issue_number) - [ ] 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/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) +### Translations (if applicable) + +- [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) + ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) diff --git a/.github/release.yml b/.github/release.yml index 2d0a9e0f9..f6ac2e4fa 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,5 +1,9 @@ changelog: categories: + - title: Breaking Changes + labels: + - break-change + - title: Bug Fixes labels: - Bug diff --git a/.github/scripts/requirements_dev.in b/.github/scripts/requirements_dev.in index a8732d927..1f65a4f4a 100644 --- a/.github/scripts/requirements_dev.in +++ b/.github/scripts/requirements_dev.in @@ -6,3 +6,4 @@ pillow unoserver opencv-python-headless pre-commit +brotli @ git+https://github.com/google/brotli.git@028fb5a23661f123017c060daa546b55cf4bde29 diff --git a/.github/scripts/requirements_dev.txt b/.github/scripts/requirements_dev.txt index 9df13c7ae..0f42b28a7 100644 --- a/.github/scripts/requirements_dev.txt +++ b/.github/scripts/requirements_dev.txt @@ -4,201 +4,98 @@ # # pip-compile --allow-unsafe --generate-hashes --output-file='.github\scripts\requirements_dev.txt' --strip-extras '.github\scripts\requirements_dev.in' # -brotli==1.1.0 \ - --hash=sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208 \ - --hash=sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48 \ - --hash=sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354 \ - --hash=sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419 \ - --hash=sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a \ - --hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \ - --hash=sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c \ - --hash=sha256:141bd4d93984070e097521ed07e2575b46f817d08f9fa42b16b9b5f27b5ac088 \ - --hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \ - --hash=sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a \ - --hash=sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3 \ - --hash=sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757 \ - --hash=sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2 \ - --hash=sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438 \ - --hash=sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578 \ - --hash=sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b \ - --hash=sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b \ - --hash=sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68 \ - --hash=sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0 \ - --hash=sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d \ - --hash=sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943 \ - --hash=sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd \ - --hash=sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409 \ - --hash=sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28 \ - --hash=sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da \ - --hash=sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50 \ - --hash=sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f \ - --hash=sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0 \ - --hash=sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547 \ - --hash=sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180 \ - --hash=sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0 \ - --hash=sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d \ - --hash=sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a \ - --hash=sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb \ - --hash=sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112 \ - --hash=sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc \ - --hash=sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2 \ - --hash=sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265 \ - --hash=sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327 \ - --hash=sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95 \ - --hash=sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec \ - --hash=sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd \ - --hash=sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c \ - --hash=sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38 \ - --hash=sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914 \ - --hash=sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0 \ - --hash=sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a \ - --hash=sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7 \ - --hash=sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368 \ - --hash=sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c \ - --hash=sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0 \ - --hash=sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f \ - --hash=sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451 \ - --hash=sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f \ - --hash=sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8 \ - --hash=sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e \ - --hash=sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248 \ - --hash=sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c \ - --hash=sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91 \ - --hash=sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724 \ - --hash=sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7 \ - --hash=sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966 \ - --hash=sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9 \ - --hash=sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97 \ - --hash=sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d \ - --hash=sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5 \ - --hash=sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf \ - --hash=sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac \ - --hash=sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b \ - --hash=sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951 \ - --hash=sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74 \ - --hash=sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648 \ - --hash=sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60 \ - --hash=sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c \ - --hash=sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1 \ - --hash=sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8 \ - --hash=sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d \ - --hash=sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc \ - --hash=sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61 \ - --hash=sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460 \ - --hash=sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751 \ - --hash=sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9 \ - --hash=sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2 \ - --hash=sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0 \ - --hash=sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1 \ - --hash=sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474 \ - --hash=sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75 \ - --hash=sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5 \ - --hash=sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f \ - --hash=sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2 \ - --hash=sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f \ - --hash=sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb \ - --hash=sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6 \ - --hash=sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9 \ - --hash=sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111 \ - --hash=sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2 \ - --hash=sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01 \ - --hash=sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467 \ - --hash=sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619 \ - --hash=sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf \ - --hash=sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408 \ - --hash=sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579 \ - --hash=sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84 \ - --hash=sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7 \ - --hash=sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c \ - --hash=sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284 \ - --hash=sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52 \ - --hash=sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b \ - --hash=sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59 \ - --hash=sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752 \ - --hash=sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1 \ - --hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \ - --hash=sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839 \ - --hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \ - --hash=sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2 \ - --hash=sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3 \ - --hash=sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64 \ - --hash=sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089 \ - --hash=sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643 \ - --hash=sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b \ - --hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e \ - --hash=sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985 \ - --hash=sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596 \ - --hash=sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2 \ - --hash=sha256:fdc3ff3bfccdc6b9cc7c342c03aa2400683f0cb891d46e94b64a197910dc4064 - # via fonttools -cffi==1.17.1 \ - --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ - --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ - --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ - --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ - --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ - --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ - --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ - --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ - --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ - --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ - --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ - --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ - --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ - --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ - --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ - --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ - --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ - --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ - --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ - --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ - --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ - --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ - --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ - --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ - --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ - --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ - --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ - --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ - --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ - --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ - --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ - --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ - --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ - --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ - --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ - --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ - --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ - --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ - --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ - --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ - --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ - --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ - --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ - --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ - --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ - --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ - --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ - --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ - --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ - --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ - --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ - --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ - --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ - --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ - --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ - --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ - --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ - --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ - --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ - --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ - --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ - --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ - --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ - --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ - --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ - --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ - --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b +# WARNING: pip install will require the following package to be hashed. +# Consider using a hashable URL like https://github.com/jazzband/pip-tools/archive/SOMECOMMIT.zip +# CVE-2025-6176 mitigation: pin brotli to a specific commit +brotli @ git+https://github.com/google/brotli.git@028fb5a23661f123017c060daa546b55cf4bde29 + # via + # -r .github/scripts/requirements_dev.in + # fonttools +cffi==2.0.0 \ + --hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \ + --hash=sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b \ + --hash=sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f \ + --hash=sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9 \ + --hash=sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44 \ + --hash=sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2 \ + --hash=sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c \ + --hash=sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75 \ + --hash=sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65 \ + --hash=sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e \ + --hash=sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a \ + --hash=sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e \ + --hash=sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25 \ + --hash=sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a \ + --hash=sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe \ + --hash=sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b \ + --hash=sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91 \ + --hash=sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592 \ + --hash=sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187 \ + --hash=sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c \ + --hash=sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1 \ + --hash=sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94 \ + --hash=sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba \ + --hash=sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb \ + --hash=sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165 \ + --hash=sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529 \ + --hash=sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca \ + --hash=sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c \ + --hash=sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6 \ + --hash=sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c \ + --hash=sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0 \ + --hash=sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743 \ + --hash=sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63 \ + --hash=sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5 \ + --hash=sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5 \ + --hash=sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4 \ + --hash=sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d \ + --hash=sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b \ + --hash=sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93 \ + --hash=sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205 \ + --hash=sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27 \ + --hash=sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512 \ + --hash=sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d \ + --hash=sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c \ + --hash=sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037 \ + --hash=sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26 \ + --hash=sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322 \ + --hash=sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb \ + --hash=sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c \ + --hash=sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8 \ + --hash=sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4 \ + --hash=sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414 \ + --hash=sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9 \ + --hash=sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664 \ + --hash=sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9 \ + --hash=sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775 \ + --hash=sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739 \ + --hash=sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc \ + --hash=sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062 \ + --hash=sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe \ + --hash=sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9 \ + --hash=sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92 \ + --hash=sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5 \ + --hash=sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13 \ + --hash=sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d \ + --hash=sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26 \ + --hash=sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f \ + --hash=sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495 \ + --hash=sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b \ + --hash=sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6 \ + --hash=sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c \ + --hash=sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef \ + --hash=sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5 \ + --hash=sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18 \ + --hash=sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad \ + --hash=sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3 \ + --hash=sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7 \ + --hash=sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5 \ + --hash=sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534 \ + --hash=sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49 \ + --hash=sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2 \ + --hash=sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5 \ + --hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \ + --hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf # via weasyprint cfgv==3.4.0 \ --hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \ @@ -212,57 +109,73 @@ distlib==0.4.0 \ --hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \ --hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d # via virtualenv -filelock==3.18.0 \ - --hash=sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2 \ - --hash=sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de +filelock==3.20.0 \ + --hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \ + --hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4 # via virtualenv -fonttools==4.59.0 \ - --hash=sha256:052444a5d0151878e87e3e512a1aa1a0ab35ee4c28afde0a778e23b0ace4a7de \ - --hash=sha256:169b99a2553a227f7b5fea8d9ecd673aa258617f466b2abc6091fe4512a0dcd0 \ - --hash=sha256:209b75943d158f610b78320eacb5539aa9e920bee2c775445b2846c65d20e19d \ - --hash=sha256:21e606b2d38fed938dde871c5736822dd6bda7a4631b92e509a1f5cd1b90c5df \ - --hash=sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d \ - --hash=sha256:26731739daa23b872643f0e4072d5939960237d540c35c14e6a06d47d71ca8fe \ - --hash=sha256:2e7cf8044ce2598bb87e44ba1d2c6e45d7a8decf56055b92906dc53f67c76d64 \ - --hash=sha256:31003b6a10f70742a63126b80863ab48175fb8272a18ca0846c0482968f0588e \ - --hash=sha256:332bfe685d1ac58ca8d62b8d6c71c2e52a6c64bc218dc8f7825c9ea51385aa01 \ - --hash=sha256:37c377f7cb2ab2eca8a0b319c68146d34a339792f9420fca6cd49cf28d370705 \ - --hash=sha256:37e01c6ec0c98599778c2e688350d624fa4770fbd6144551bd5e032f1199171c \ - --hash=sha256:401b1941ce37e78b8fd119b419b617277c65ae9417742a63282257434fd68ea2 \ - --hash=sha256:4536f2695fe5c1ffb528d84a35a7d3967e5558d2af58b4775e7ab1449d65767b \ - --hash=sha256:4c908a7036f0f3677f8afa577bcd973e3e20ddd2f7c42a33208d18bee95cdb6f \ - --hash=sha256:51ab1ff33c19e336c02dee1e9fd1abd974a4ca3d8f7eef2a104d0816a241ce97 \ - --hash=sha256:524133c1be38445c5c0575eacea42dbd44374b310b1ffc4b60ff01d881fabb96 \ - --hash=sha256:57bb7e26928573ee7c6504f54c05860d867fd35e675769f3ce01b52af38d48e2 \ - --hash=sha256:60f6665579e909b618282f3c14fa0b80570fbf1ee0e67678b9a9d43aa5d67a37 \ - --hash=sha256:62224a9bb85b4b66d1b46d45cbe43d71cbf8f527d332b177e3b96191ffbc1e64 \ - --hash=sha256:6770d7da00f358183d8fd5c4615436189e4f683bdb6affb02cad3d221d7bb757 \ - --hash=sha256:6801aeddb6acb2c42eafa45bc1cb98ba236871ae6f33f31e984670b749a8e58e \ - --hash=sha256:70d6b3ceaa9cc5a6ac52884f3b3d9544e8e231e95b23f138bdb78e6d4dc0eae3 \ - --hash=sha256:78813b49d749e1bb4db1c57f2d4d7e6db22c253cb0a86ad819f5dc197710d4b2 \ - --hash=sha256:841b2186adce48903c0fef235421ae21549020eca942c1da773ac380b056ab3c \ - --hash=sha256:84fc186980231a287b28560d3123bd255d3c6b6659828c642b4cf961e2b923d0 \ - --hash=sha256:885bde7d26e5b40e15c47bd5def48b38cbd50830a65f98122a8fb90962af7cd1 \ - --hash=sha256:8b4309a2775e4feee7356e63b163969a215d663399cce1b3d3b65e7ec2d9680e \ - --hash=sha256:8d77f92438daeaddc05682f0f3dac90c5b9829bcac75b57e8ce09cb67786073c \ - --hash=sha256:902425f5afe28572d65d2bf9c33edd5265c612ff82c69e6f83ea13eafc0dcbea \ - --hash=sha256:9bcc1e77fbd1609198966ded6b2a9897bd6c6bcbd2287a2fc7d75f1a254179c5 \ - --hash=sha256:a408c3c51358c89b29cfa5317cf11518b7ce5de1717abb55c5ae2d2921027de6 \ - --hash=sha256:a9bf8adc9e1f3012edc8f09b08336272aec0c55bc677422273e21280db748f7c \ - --hash=sha256:b818db35879d2edf7f46c7e729c700a0bce03b61b9412f5a7118406687cb151d \ - --hash=sha256:b8974b2a266b54c96709bd5e239979cddfd2dbceed331aa567ea1d7c4a2202db \ - --hash=sha256:be392ec3529e2f57faa28709d60723a763904f71a2b63aabe14fee6648fe3b14 \ - --hash=sha256:d3972b13148c1d1fbc092b27678a33b3080d1ac0ca305742b0119b75f9e87e38 \ - --hash=sha256:d40dcf533ca481355aa7b682e9e079f766f35715defa4929aeb5597f9604272e \ - --hash=sha256:e93df708c69a193fc7987192f94df250f83f3851fda49413f02ba5dded639482 \ - --hash=sha256:efd7e6660674e234e29937bc1481dceb7e0336bfae75b856b4fb272b5093c5d4 \ - --hash=sha256:f9b3a78f69dcbd803cf2fb3f972779875b244c1115481dfbdd567b2c22b31f6b \ - --hash=sha256:fa39475eaccb98f9199eccfda4298abaf35ae0caec676ffc25b3a5e224044464 \ - --hash=sha256:fbce6dae41b692a5973d0f2158f782b9ad05babc2c2019a970a1094a23909b1b +fonttools==4.60.1 \ + --hash=sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c \ + --hash=sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc \ + --hash=sha256:0b0835ed15dd5b40d726bb61c846a688f5b4ce2208ec68779bc81860adb5851a \ + --hash=sha256:0eae96373e4b7c9e45d099d7a523444e3554360927225c1cdae221a58a45b856 \ + --hash=sha256:122e1a8ada290423c493491d002f622b1992b1ab0b488c68e31c413390dc7eb2 \ + --hash=sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259 \ + --hash=sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c \ + --hash=sha256:1525796c3ffe27bb6268ed2a1bb0dcf214d561dfaf04728abf01489eb5339dce \ + --hash=sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003 \ + --hash=sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272 \ + --hash=sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77 \ + --hash=sha256:268ecda8ca6cb5c4f044b1fb9b3b376e8cd1b361cef275082429dc4174907038 \ + --hash=sha256:282dafa55f9659e8999110bd8ed422ebe1c8aecd0dc396550b038e6c9a08b8ea \ + --hash=sha256:2ee06fc57512144d8b0445194c2da9f190f61ad51e230f14836286470c99f854 \ + --hash=sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2 \ + --hash=sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258 \ + --hash=sha256:4ba4bd646e86de16160f0fb72e31c3b9b7d0721c3e5b26b9fa2fc931dfdb2652 \ + --hash=sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08 \ + --hash=sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99 \ + --hash=sha256:596ecaca36367027d525b3b426d8a8208169d09edcf8c7506aceb3a38bfb55c7 \ + --hash=sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914 \ + --hash=sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6 \ + --hash=sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed \ + --hash=sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb \ + --hash=sha256:7473a8ed9ed09aeaa191301244a5a9dbe46fe0bf54f9d6cd21d83044c3321217 \ + --hash=sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc \ + --hash=sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f \ + --hash=sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c \ + --hash=sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877 \ + --hash=sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801 \ + --hash=sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85 \ + --hash=sha256:8b4eb332f9501cb1cd3d4d099374a1e1306783ff95489a1026bde9eb02ccc34a \ + --hash=sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb \ + --hash=sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383 \ + --hash=sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401 \ + --hash=sha256:9a52f254ce051e196b8fe2af4634c2d2f02c981756c6464dc192f1b6050b4e28 \ + --hash=sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01 \ + --hash=sha256:a140761c4ff63d0cb9256ac752f230460ee225ccef4ad8f68affc723c88e2036 \ + --hash=sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc \ + --hash=sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac \ + --hash=sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903 \ + --hash=sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3 \ + --hash=sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6 \ + --hash=sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c \ + --hash=sha256:b42d86938e8dda1cd9a1a87a6d82f1818eaf933348429653559a458d027446da \ + --hash=sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299 \ + --hash=sha256:c7420a2696a44650120cdd269a5d2e56a477e2bfa9d95e86229059beb1c19e15 \ + --hash=sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199 \ + --hash=sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf \ + --hash=sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1 \ + --hash=sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537 \ + --hash=sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d \ + --hash=sha256:ee0c0b3b35b34f782afc673d503167157094a16f442ace7c6c5e0ca80b08f50c \ + --hash=sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4 \ + --hash=sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9 \ + --hash=sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed \ + --hash=sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987 \ + --hash=sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa # via weasyprint -identify==2.6.13 \ - --hash=sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b \ - --hash=sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32 +identify==2.6.15 \ + --hash=sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757 \ + --hash=sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf # via pre-commit nodeenv==1.9.1 \ --hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \ @@ -338,128 +251,113 @@ pdf2image==1.17.0 \ --hash=sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57 \ --hash=sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2 # via -r .github/scripts/requirements_dev.in -pillow==11.3.0 \ - --hash=sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2 \ - --hash=sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214 \ - --hash=sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e \ - --hash=sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59 \ - --hash=sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50 \ - --hash=sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632 \ - --hash=sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06 \ - --hash=sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a \ - --hash=sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51 \ - --hash=sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced \ - --hash=sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f \ - --hash=sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12 \ - --hash=sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8 \ - --hash=sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6 \ - --hash=sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580 \ - --hash=sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f \ - --hash=sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac \ - --hash=sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860 \ - --hash=sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd \ - --hash=sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722 \ - --hash=sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8 \ - --hash=sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4 \ - --hash=sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673 \ - --hash=sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788 \ - --hash=sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542 \ - --hash=sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e \ - --hash=sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd \ - --hash=sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8 \ - --hash=sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523 \ - --hash=sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967 \ - --hash=sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809 \ - --hash=sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477 \ - --hash=sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027 \ - --hash=sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae \ - --hash=sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b \ - --hash=sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c \ - --hash=sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f \ - --hash=sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e \ - --hash=sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b \ - --hash=sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7 \ - --hash=sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27 \ - --hash=sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361 \ - --hash=sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae \ - --hash=sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d \ - --hash=sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc \ - --hash=sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58 \ - --hash=sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad \ - --hash=sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6 \ - --hash=sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024 \ - --hash=sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978 \ - --hash=sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb \ - --hash=sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d \ - --hash=sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0 \ - --hash=sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9 \ - --hash=sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f \ - --hash=sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874 \ - --hash=sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa \ - --hash=sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081 \ - --hash=sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149 \ - --hash=sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6 \ - --hash=sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d \ - --hash=sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd \ - --hash=sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f \ - --hash=sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c \ - --hash=sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31 \ - --hash=sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e \ - --hash=sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db \ - --hash=sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6 \ - --hash=sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f \ - --hash=sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494 \ - --hash=sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69 \ - --hash=sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94 \ - --hash=sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77 \ - --hash=sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d \ - --hash=sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7 \ - --hash=sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a \ - --hash=sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438 \ - --hash=sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288 \ - --hash=sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b \ - --hash=sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635 \ - --hash=sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3 \ - --hash=sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d \ - --hash=sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe \ - --hash=sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0 \ - --hash=sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe \ - --hash=sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a \ - --hash=sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805 \ - --hash=sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8 \ - --hash=sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36 \ - --hash=sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a \ - --hash=sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b \ - --hash=sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e \ - --hash=sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25 \ - --hash=sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12 \ - --hash=sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada \ - --hash=sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c \ - --hash=sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71 \ - --hash=sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d \ - --hash=sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c \ - --hash=sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6 \ - --hash=sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1 \ - --hash=sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50 \ - --hash=sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653 \ - --hash=sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c \ - --hash=sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4 \ - --hash=sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3 +pillow==12.0.0 \ + --hash=sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643 \ + --hash=sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e \ + --hash=sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e \ + --hash=sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc \ + --hash=sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642 \ + --hash=sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6 \ + --hash=sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1 \ + --hash=sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b \ + --hash=sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399 \ + --hash=sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba \ + --hash=sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad \ + --hash=sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47 \ + --hash=sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739 \ + --hash=sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b \ + --hash=sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f \ + --hash=sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10 \ + --hash=sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52 \ + --hash=sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d \ + --hash=sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b \ + --hash=sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a \ + --hash=sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9 \ + --hash=sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d \ + --hash=sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098 \ + --hash=sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905 \ + --hash=sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b \ + --hash=sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3 \ + --hash=sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371 \ + --hash=sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953 \ + --hash=sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01 \ + --hash=sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca \ + --hash=sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e \ + --hash=sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7 \ + --hash=sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27 \ + --hash=sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082 \ + --hash=sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e \ + --hash=sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d \ + --hash=sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8 \ + --hash=sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a \ + --hash=sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad \ + --hash=sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3 \ + --hash=sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a \ + --hash=sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d \ + --hash=sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353 \ + --hash=sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee \ + --hash=sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b \ + --hash=sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b \ + --hash=sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a \ + --hash=sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7 \ + --hash=sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef \ + --hash=sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a \ + --hash=sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a \ + --hash=sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257 \ + --hash=sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07 \ + --hash=sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4 \ + --hash=sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c \ + --hash=sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c \ + --hash=sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4 \ + --hash=sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe \ + --hash=sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8 \ + --hash=sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5 \ + --hash=sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6 \ + --hash=sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e \ + --hash=sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8 \ + --hash=sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e \ + --hash=sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275 \ + --hash=sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3 \ + --hash=sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76 \ + --hash=sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227 \ + --hash=sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9 \ + --hash=sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5 \ + --hash=sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79 \ + --hash=sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca \ + --hash=sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa \ + --hash=sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b \ + --hash=sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e \ + --hash=sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197 \ + --hash=sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab \ + --hash=sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79 \ + --hash=sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2 \ + --hash=sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363 \ + --hash=sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0 \ + --hash=sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e \ + --hash=sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782 \ + --hash=sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925 \ + --hash=sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0 \ + --hash=sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b \ + --hash=sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced \ + --hash=sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c \ + --hash=sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344 \ + --hash=sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9 \ + --hash=sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1 # via # -r .github/scripts/requirements_dev.in # pdf2image # weasyprint -platformdirs==4.3.8 \ - --hash=sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc \ - --hash=sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4 +platformdirs==4.5.0 \ + --hash=sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312 \ + --hash=sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3 # via virtualenv pre-commit==4.3.0 \ --hash=sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8 \ --hash=sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16 # via -r .github/scripts/requirements_dev.in -pycparser==2.22 \ - --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ - --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc +pycparser==2.23 \ + --hash=sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2 \ + --hash=sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934 # via cffi pydyf==0.11.0 \ --hash=sha256:0aaf9e2ebbe786ec7a78ec3fbffa4cdcecde53fd6f563221d53c6bc1328848a3 \ @@ -469,60 +367,80 @@ pyphen==0.17.2 \ --hash=sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd \ --hash=sha256:f60647a9c9b30ec6c59910097af82bc5dd2d36576b918e44148d8b07ef3b4aa3 # via weasyprint -pyyaml==6.0.2 \ - --hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \ - --hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \ - --hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \ - --hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \ - --hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \ - --hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \ - --hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \ - --hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \ - --hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \ - --hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \ - --hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \ - --hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \ - --hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \ - --hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \ - --hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \ - --hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \ - --hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \ - --hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \ - --hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \ - --hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \ - --hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \ - --hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \ - --hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \ - --hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \ - --hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \ - --hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \ - --hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \ - --hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \ - --hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \ - --hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \ - --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \ - --hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \ - --hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \ - --hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \ - --hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \ - --hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \ - --hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \ - --hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \ - --hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \ - --hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \ - --hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \ - --hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \ - --hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \ - --hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \ - --hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \ - --hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \ - --hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \ - --hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \ - --hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \ - --hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \ - --hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \ - --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \ - --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4 +pyyaml==6.0.3 \ + --hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \ + --hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \ + --hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \ + --hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \ + --hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \ + --hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \ + --hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \ + --hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \ + --hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \ + --hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \ + --hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \ + --hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \ + --hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \ + --hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \ + --hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \ + --hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \ + --hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \ + --hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \ + --hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \ + --hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \ + --hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \ + --hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \ + --hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \ + --hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \ + --hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \ + --hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \ + --hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \ + --hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \ + --hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \ + --hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \ + --hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \ + --hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \ + --hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \ + --hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \ + --hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \ + --hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \ + --hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \ + --hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \ + --hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \ + --hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \ + --hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \ + --hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \ + --hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \ + --hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \ + --hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \ + --hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \ + --hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \ + --hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \ + --hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \ + --hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \ + --hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \ + --hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \ + --hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \ + --hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \ + --hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \ + --hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \ + --hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \ + --hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \ + --hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \ + --hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \ + --hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \ + --hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \ + --hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \ + --hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \ + --hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \ + --hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \ + --hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \ + --hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \ + --hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \ + --hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \ + --hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \ + --hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \ + --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 # via pre-commit tinycss2==1.4.0 \ --hash=sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7 \ @@ -534,13 +452,13 @@ tinyhtml5==2.0.0 \ --hash=sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc \ --hash=sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e # via weasyprint -unoserver==3.3.2 \ - --hash=sha256:1eeb7467cf6b56b8eff3b576e2d1b2b2ff4e0eb2052e995ac80a1456de300639 \ - --hash=sha256:87e144f903ee21951b2e06a97549450c13ed7eca5bcebad942d3352d4e882616 +unoserver==3.4 \ + --hash=sha256:3dcf2204013def1d1ddd3671f38b11346bdf349fef9728277462666a8a634419 \ + --hash=sha256:64c24d33d4f65d680a2d9f676518cb28e7fd6c1f9d9a745c33e4a4cb59afdfcd # via -r .github/scripts/requirements_dev.in -virtualenv==20.33.1 \ - --hash=sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67 \ - --hash=sha256:1b44478d9e261b3fb8baa5e74a0ca3bc0e05f21aa36167bf9cbf850e542765b8 +virtualenv==20.35.4 \ + --hash=sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c \ + --hash=sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b # via pre-commit weasyprint==66.0 \ --hash=sha256:82b0783b726fcd318e2c977dcdddca76515b30044bc7a830cc4fbe717582a6d0 \ @@ -628,9 +546,9 @@ zopfli==0.2.3.post1 \ # via fonttools # The following packages are considered to be unsafe in a requirements file: -pip==25.2 \ - --hash=sha256:578283f006390f85bb6282dffb876454593d637f5d1be494b5202ce4877e71f2 \ - --hash=sha256:6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717 +pip==25.3 \ + --hash=sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343 \ + --hash=sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd # via -r .github/scripts/requirements_dev.in setuptools==80.9.0 \ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \ diff --git a/.github/scripts/requirements_pre_commit.txt b/.github/scripts/requirements_pre_commit.txt index 60b304142..459e46c2c 100644 --- a/.github/scripts/requirements_pre_commit.txt +++ b/.github/scripts/requirements_pre_commit.txt @@ -12,9 +12,9 @@ distlib==0.4.0 \ --hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \ --hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d # via virtualenv -filelock==3.19.1 \ - --hash=sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58 \ - --hash=sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d +filelock==3.20.0 \ + --hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \ + --hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4 # via virtualenv identify==2.6.15 \ --hash=sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757 \ @@ -24,9 +24,9 @@ nodeenv==1.9.1 \ --hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \ --hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9 # via pre-commit -platformdirs==4.4.0 \ - --hash=sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85 \ - --hash=sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf +platformdirs==4.5.0 \ + --hash=sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312 \ + --hash=sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3 # via virtualenv pre-commit==4.3.0 \ --hash=sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8 \ @@ -107,7 +107,7 @@ pyyaml==6.0.3 \ --hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \ --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 # via pre-commit -virtualenv==20.34.0 \ - --hash=sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026 \ - --hash=sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a +virtualenv==20.35.4 \ + --hash=sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c \ + --hash=sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b # via pre-commit diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index c7aa66d4e..edb5f273a 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -41,12 +41,12 @@ jobs: enable_enterprise: ${{ steps.check-pro-flag.outputs.enable_enterprise }} steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout PR - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup GitHub App Bot if: github.actor != 'dependabot[bot]' @@ -129,12 +129,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout PR - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup GitHub App Bot if: github.actor != 'dependabot[bot]' @@ -146,7 +146,7 @@ jobs: private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - name: Checkout PR - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: refs/pull/${{ needs.check-comment.outputs.pr_number }}/merge token: ${{ steps.setup-bot.outputs.token }} @@ -357,3 +357,149 @@ jobs: rm -f ../private.key docker-compose.yml echo "Cleanup complete." continue-on-error: true + + handle-label-commands: + if: ${{ github.event.issue.pull_request != null }} + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 + with: + egress-policy: audit + + - name: Check out the repository + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + + - name: Setup GitHub App Bot + id: setup-bot + uses: ./.github/actions/setup-bot + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + + - name: Apply label commands + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + github-token: ${{ steps.setup-bot.outputs.token }} + script: | + const fs = require('fs'); + const path = require('path'); + + const { comment, issue } = context.payload; + const commentBody = comment?.body ?? ''; + if (!commentBody.includes('::label::')) { + core.info('No label commands detected in comment.'); + return; + } + + const configPath = path.join(process.env.GITHUB_WORKSPACE, '.github', 'config', 'repo_devs.json'); + const repoDevsConfig = JSON.parse(fs.readFileSync(configPath, 'utf8')); + const label_changer = (repoDevsConfig.label_changer || []).map((login) => login.toLowerCase()); + + const commenter = (comment?.user?.login || '').toLowerCase(); + if (!label_changer.includes(commenter)) { + core.info(`User ${commenter} is not authorized to manage labels.`); + return; + } + + const labelsConfigPath = path.join(process.env.GITHUB_WORKSPACE, '.github', 'labels.yml'); + const labelsFile = fs.readFileSync(labelsConfigPath, 'utf8'); + + const labelNameMap = new Map(); + for (const match of labelsFile.matchAll(/-\s+name:\s*(?:"([^"]+)"|'([^']+)'|([^\n]+))/g)) { + const labelName = (match[1] ?? match[2] ?? match[3] ?? '').trim(); + + if (!labelName) { + continue; + } + const normalized = labelName.toLowerCase(); + if (!labelNameMap.has(normalized)) { + labelNameMap.set(normalized, labelName); + } + } + + if (!labelNameMap.size) { + core.warning('No labels could be read from .github/labels.yml; aborting label commands.'); + return; + } + + let allowedLabelNames = new Set(labelNameMap.values()); + + const labelsToAdd = new Set(); + const labelsToRemove = new Set(); + const commandRegex = /^(\w+)::(label)::"([^"]+)"/gim; + let match; + while ((match = commandRegex.exec(commentBody)) !== null) { + core.info(`Found label command: ${match[0]} (action: ${match[1]}, label: ${match[2]}, labelName: ${match[3]})`); + const action = match[1].toLowerCase(); + const labelName = match[3].trim(); + + if (!labelName) { + continue; + } + + const normalized = labelName.toLowerCase(); + const resolvedLabelName = labelNameMap.get(normalized); + if (action === 'add') { + if (!resolvedLabelName) { + core.warning(`Label "${labelName}" is not defined in .github/labels.yml and cannot be added.`); + continue; + } + if (!allowedLabelNames.has(resolvedLabelName)) { + core.warning(`Label "${resolvedLabelName}" is not allowed for add commands and will be skipped.`); + continue; + } + labelsToAdd.add(resolvedLabelName); + } else if (action === 'rm') { + const labelToRemove = resolvedLabelName ?? labelName; + if (!resolvedLabelName) { + core.warning(`Label "${labelName}" is not defined in .github/labels.yml; attempting to remove as provided.`); + } + labelsToRemove.add(labelToRemove); + } + } + + const addLabels = Array.from(labelsToAdd); + const removeLabels = Array.from(labelsToRemove); + + if (!addLabels.length && !removeLabels.length) { + core.info('No valid label commands found after parsing.'); + return; + } + + const issueParams = { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + }; + + if (addLabels.length) { + core.info(`Adding labels: ${addLabels.join(', ')}`); + await github.rest.issues.addLabels({ + ...issueParams, + labels: addLabels, + }); + } + + for (const labelName of removeLabels) { + core.info(`Removing label: ${labelName}`); + try { + await github.rest.issues.removeLabel({ + ...issueParams, + name: labelName, + }); + } catch (error) { + if (error.status === 404) { + core.warning(`Label "${labelName}" was not present on the pull request.`); + } else { + throw error; + } + } + } + + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: comment.id, + }); + core.info('Processed label commands and deleted the comment.'); diff --git a/.github/workflows/PR-Demo-cleanup.yml b/.github/workflows/PR-Demo-cleanup.yml index 47f1e8ed9..621322df7 100644 --- a/.github/workflows/PR-Demo-cleanup.yml +++ b/.github/workflows/PR-Demo-cleanup.yml @@ -21,12 +21,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout PR - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup GitHub App Bot if: github.actor != 'dependabot[bot]' diff --git a/.github/workflows/ai_pr_title_review.yml b/.github/workflows/ai_pr_title_review.yml index 77668d69a..e93a0dc39 100644 --- a/.github/workflows/ai_pr_title_review.yml +++ b/.github/workflows/ai_pr_title_review.yml @@ -19,11 +19,11 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/auto-labelerV2.yml b/.github/workflows/auto-labelerV2.yml index d66ea570a..d776aa7ac 100644 --- a/.github/workflows/auto-labelerV2.yml +++ b/.github/workflows/auto-labelerV2.yml @@ -2,6 +2,9 @@ name: "Auto Pull Request Labeler V2" on: pull_request_target: types: [opened, synchronize] + branches: + - main + - V2 permissions: contents: read @@ -13,11 +16,11 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup GitHub App Bot id: setup-bot diff --git a/.github/workflows/check_toml.yml b/.github/workflows/check_toml.yml index 8fc1a75b8..4cf04ea15 100644 --- a/.github/workflows/check_toml.yml +++ b/.github/workflows/check_toml.yml @@ -25,12 +25,12 @@ jobs: pull-requests: write # Allow writing to pull requests steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout main branch first - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup GitHub App Bot id: setup-bot diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index a35b32c15..923123e94 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,13 +17,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: "Checkout Repository" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: "Dependency Review" - uses: actions/dependency-review-action@56339e523c0409420f6c2c9a2f4292bbb3c07dd3 # v4.8.0 + uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 with: config-file: './.github/config/dependency-review-config.yml' diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index a3dadc272..7685c013a 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -31,12 +31,12 @@ jobs: repository-projects: write # Required for enabling automerge steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Check out code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 @@ -64,7 +64,7 @@ jobs: - name: Upload artifact on failure if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: dependencies-without-allowed-license.json path: build/reports/dependency-license/dependencies-without-allowed-license.json @@ -82,7 +82,7 @@ jobs: - name: Create Pull Request id: cpr if: env.CHANGES_DETECTED == 'true' - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9 with: token: ${{ steps.setup-bot.outputs.token }} commit-message: "Update 3rd Party Licenses" diff --git a/.github/workflows/manage-label.yml b/.github/workflows/manage-label.yml index d480249f2..ee6bb3492 100644 --- a/.github/workflows/manage-label.yml +++ b/.github/workflows/manage-label.yml @@ -15,12 +15,12 @@ jobs: issues: write steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Check out the repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run Labeler uses: crazy-max/ghaction-github-labeler@24d110aa46a59976b8a7f35518cb7f14f434c916 # v5.3.0 diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index 07c03b083..8e4bfeef8 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -38,14 +38,14 @@ jobs: version: ${{ steps.versionNumber.outputs.versionNumber }} steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: java-version: "21" distribution: "temurin" @@ -106,14 +106,14 @@ jobs: file_suffix: "-server" steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: java-version: "21" distribution: "temurin" @@ -145,7 +145,7 @@ jobs: cp app/core/build/libs/stirling-pdf-${{ needs.determine-matrix.outputs.version }}.jar ./jar-dist/Stirling-PDF${{ matrix.variant.file_suffix }}.jar - name: Upload JAR artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: jar${{ matrix.variant.file_suffix }} path: ./jar-dist/*.jar @@ -189,7 +189,7 @@ jobs: targets: ${{ (matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: java-version: "21" distribution: "temurin" @@ -516,7 +516,7 @@ jobs: fi - name: Upload build artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: Stirling-PDF-${{ matrix.name }} path: ./dist/* @@ -530,30 +530,30 @@ jobs: contents: write steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Download all Tauri artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: pattern: Stirling-PDF-* path: ./artifacts/tauri - name: Download JAR artifact (default) - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: jar path: ./artifacts/jars - name: Download JAR artifact (with login) - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: jar-with-login path: ./artifacts/jars - name: Download JAR artifact (server only) - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: jar-server path: ./artifacts/jars @@ -562,7 +562,7 @@ jobs: run: ls -R ./artifacts - name: Upload binaries to Release - uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4 + uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2 with: tag_name: v${{ needs.determine-matrix.outputs.version }} generate_release_notes: true diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml index acd489f5b..9466788b1 100644 --- a/.github/workflows/pre_commit.yml +++ b/.github/workflows/pre_commit.yml @@ -21,12 +21,12 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 @@ -67,7 +67,7 @@ jobs: - name: Create Pull Request if: env.CHANGES_DETECTED == 'true' - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9 with: token: ${{ steps.setup-bot.outputs.token }} commit-message: ":file_folder: pre-commit" diff --git a/.github/workflows/push-docker-v2.yml b/.github/workflows/push-docker-v2.yml index 061cf40ed..bea7d44ac 100644 --- a/.github/workflows/push-docker-v2.yml +++ b/.github/workflows/push-docker-v2.yml @@ -5,7 +5,7 @@ on: push: branches: - V2-master - - alljavadocker + - V1_V2_merge # cancel in-progress jobs if a new job is triggered # This is useful to avoid running multiple builds for the same branch if a new commit is pushed @@ -95,10 +95,10 @@ jobs: type=raw,value=${{ steps.versionNumber.outputs.versionNumber }} type=raw,value=latest - - name: Generate tags for latest (alljavadocker branch - test) + - name: Generate tags for latest (V1_V2_merge branch - test) id: meta-test uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 - if: github.ref == 'refs/heads/alljavadocker' + if: github.ref == 'refs/heads/V1_V2_merge' with: images: | ghcr.io/stirling-tools/stirling-pdf-test @@ -151,10 +151,10 @@ jobs: type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat type=raw,value=latest-fat - - name: Generate tags for latest-fat (alljavadocker branch - test) + - name: Generate tags for latest-fat (V1_V2_merge branch - test) id: meta-fat-test uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 - if: github.ref == 'refs/heads/alljavadocker' + if: github.ref == 'refs/heads/V1_V2_merge' with: images: | ghcr.io/stirling-tools/stirling-pdf-test @@ -205,10 +205,10 @@ jobs: type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite type=raw,value=latest-ultra-lite - - name: Generate tags for ultra-lite (alljavadocker branch - test) + - name: Generate tags for ultra-lite (V1_V2_merge branch - test) id: meta-lite-test uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 - if: github.ref == 'refs/heads/alljavadocker' + if: github.ref == 'refs/heads/V1_V2_merge' with: images: | ghcr.io/stirling-tools/stirling-pdf-test diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml index ecf3fdc95..881def760 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -31,11 +31,11 @@ jobs: id-token: write steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up JDK 17 uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -55,7 +55,7 @@ jobs: - name: Install cosign if: github.ref == 'refs/heads/master' - uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0 + uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 with: cosign-release: "v2.4.1" @@ -81,7 +81,7 @@ jobs: password: ${{ github.token }} - name: Set up QEMU - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Convert repository owner to lowercase id: repoowner @@ -89,7 +89,7 @@ jobs: - name: Generate tags id: meta - uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 + uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 if: github.ref != 'refs/heads/main' with: images: | @@ -135,7 +135,7 @@ jobs: - name: Generate tags ultra-lite id: meta2 - uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 + uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 if: github.ref != 'refs/heads/main' with: images: | @@ -166,7 +166,7 @@ jobs: - name: Generate tags fat id: meta3 - uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 + uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 with: images: | ${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf diff --git a/.github/workflows/releaseArtifacts.yml b/.github/workflows/releaseArtifacts.yml index 70cfced99..924efe36a 100644 --- a/.github/workflows/releaseArtifacts.yml +++ b/.github/workflows/releaseArtifacts.yml @@ -26,7 +26,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} version: ${{ steps.versionNumber.outputs.versionNumber }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Get version number id: versionNumber @@ -68,12 +68,12 @@ jobs: WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} steps: - name: Harden Runner - uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-22.04' @@ -95,7 +95,7 @@ jobs: targets: ${{ (matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - name: Set up JDK 21 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: java-version: "21" distribution: "temurin" @@ -448,7 +448,7 @@ jobs: egress-policy: audit - name: Download build artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: Stirling-PDF-${{ matrix.name }} @@ -517,7 +517,7 @@ jobs: egress-policy: audit - name: Download all signed artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: pattern: Stirling-PDF-*-signed path: ./artifacts @@ -526,7 +526,7 @@ jobs: run: ls -R ./artifacts - name: Create GitHub Release - uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4 + uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2 with: tag_name: v${{ needs.determine-matrix.outputs.version }} generate_release_notes: true diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d83accd49..ab5fdd583 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -35,12 +35,12 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: "Checkout code" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false @@ -67,7 +67,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif @@ -75,6 +75,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.29.5 + uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v3.29.5 with: sarif_file: results.sarif diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml deleted file mode 100644 index dd419b310..000000000 --- a/.github/workflows/sonarqube.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Run Sonarqube - -on: - push: - branches: - - master - pull_request_target: - branches: - - main - workflow_dispatch: - -# cancel in-progress jobs if a new job is triggered -# This is useful to avoid running multiple builds for the same branch if a new commit is pushed -# or a pull request is updated. -# It helps to save resources and time by ensuring that only the latest commit is built and tested -# This is particularly useful for long-running jobs that may take a while to complete. -# The `group` is set to a combination of the workflow name, event name, and branch name. -# This ensures that jobs are grouped by the workflow and branch, allowing for cancellation of -# in-progress jobs when a new commit is pushed to the same branch or a new pull request is opened. -concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref_name || github.ref }} - cancel-in-progress: true - -permissions: - pull-requests: read - actions: read - -jobs: - sonarqube: - if: ${{ vars.CI_PROFILE != 'lite' }} - runs-on: ubuntu-latest - steps: - - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 - with: - egress-policy: audit - - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - fetch-depth: 0 - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - - - name: Build and analyze with Gradle - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - DISABLE_ADDITIONAL_FEATURES: false - STIRLING_PDF_DESKTOP_UI: true - run: | - ./gradlew clean build sonar \ - -Dsonar.projectKey=Stirling-Tools_Stirling-PDF \ - -Dsonar.organization=stirling-tools \ - -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.login=${SONAR_TOKEN} \ - -Dsonar.log.level=DEBUG \ - --info - - - name: Upload Problems Report on Failure - if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: gradle-problems-report - path: build/reports/problems/problems-report.html - retention-days: 7 - - - name: Upload Sonar Logs on Failure - if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: sonar-logs - path: | - .scannerwork/report-task.txt - build/sonar/ - retention-days: 7 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c53bb4a4b..eb44ce0ce 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 6e9cdb435..0fc542496 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -27,11 +27,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up JDK 17 uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 diff --git a/.github/workflows/sync_files_v2.yml b/.github/workflows/sync_files_v2.yml index 935252be2..ae45f85fd 100644 --- a/.github/workflows/sync_files_v2.yml +++ b/.github/workflows/sync_files_v2.yml @@ -33,11 +33,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup GitHub App Bot id: setup-bot @@ -47,7 +47,7 @@ jobs: private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: "3.12" cache: "pip" # caching pip dependencies diff --git a/.github/workflows/testdriver.yml b/.github/workflows/testdriver.yml index 12d5bc48d..59bf2824f 100644 --- a/.github/workflows/testdriver.yml +++ b/.github/workflows/testdriver.yml @@ -25,12 +25,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up JDK uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -125,7 +125,7 @@ jobs: outputs: frontend: ${{ steps.changes.outputs.frontend }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Check for file changes uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 @@ -140,14 +140,14 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up Node - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: cache: 'npm' cache-dependency-path: frontend/package-lock.json @@ -176,7 +176,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a97b3a2a8..d4c63e8a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.7 + rev: v0.14.2 hooks: - id: ruff args: @@ -26,7 +26,7 @@ repos: hooks: - id: gitleaks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: end-of-file-fixer files: ^.*(\.js|\.java|\.py|\.yml)$ diff --git a/app/common/build.gradle b/app/common/build.gradle index e2184a4a0..313eecdf8 100644 --- a/app/common/build.gradle +++ b/app/common/build.gradle @@ -33,16 +33,16 @@ dependencies { 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 'org.apache.commons:commons-lang3:3.19.0' + api 'org.apache.commons:commons-lang3:3.20.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 "org.apache.pdfbox:xmpbox:$pdfboxVersion" api "org.apache.pdfbox:preflight:$pdfboxVersion" - api 'com.github.junrar:junrar:7.5.5' // RAR archive support for CBR files + api 'com.github.junrar:junrar:7.5.7' // RAR archive support for CBR files api 'jakarta.servlet:jakarta.servlet-api:6.1.0' api 'org.snakeyaml:snakeyaml-engine:2.10' - api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.13" + api "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.14" api 'jakarta.mail:jakarta.mail-api:2.1.5' runtimeOnly 'org.eclipse.angus:angus-mail:2.0.5' } diff --git a/app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java index ff48b5b2e..80331405d 100644 --- a/app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java +++ b/app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java @@ -334,6 +334,9 @@ public class EndpointConfiguration { addEndpointToGroup("Convert", "pdf-to-csv"); addEndpointToGroup("Convert", "pdf-to-markdown"); addEndpointToGroup("Convert", "eml-to-pdf"); + addEndpointToGroup("Convert", "pdf-to-vector"); + addEndpointToGroup("Convert", "vector-to-pdf"); + addEndpointToGroup("Convert", "pdf-to-video"); addEndpointToGroup("Convert", "cbz-to-pdf"); addEndpointToGroup("Convert", "pdf-to-cbz"); addEndpointToGroup("Convert", "pdf-to-json"); @@ -490,6 +493,10 @@ public class EndpointConfiguration { /* Ghostscript */ addEndpointToGroup("Ghostscript", "repair"); addEndpointToGroup("Ghostscript", "compress-pdf"); + addEndpointToGroup("Ghostscript", "crop"); + addEndpointToGroup("Ghostscript", "replace-invert-pdf"); + addEndpointToGroup("Ghostscript", "pdf-to-vector"); + addEndpointToGroup("Ghostscript", "vector-to-pdf"); /* ImageMagick */ addEndpointToGroup("ImageMagick", "compress-pdf"); @@ -554,7 +561,7 @@ public class EndpointConfiguration { disableGroup("enterprise"); } - if (!applicationProperties.getSystem().getEnableUrlToPDF()) { + if (!applicationProperties.getSystem().isEnableUrlToPDF()) { disableEndpoint("url-to-pdf"); } } diff --git a/app/common/src/main/java/stirling/software/common/aop/AutoJobAspect.java b/app/common/src/main/java/stirling/software/common/aop/AutoJobAspect.java index ac36cd0d7..5e7ce1327 100644 --- a/app/common/src/main/java/stirling/software/common/aop/AutoJobAspect.java +++ b/app/common/src/main/java/stirling/software/common/aop/AutoJobAspect.java @@ -37,7 +37,7 @@ public class AutoJobAspect { @Around("@annotation(autoJobPostMapping)") public Object wrapWithJobExecution( - ProceedingJoinPoint joinPoint, AutoJobPostMapping autoJobPostMapping) { + ProceedingJoinPoint joinPoint, AutoJobPostMapping autoJobPostMapping) throws Exception { // This aspect will run before any audit aspects due to @Order(0) // Extract parameters from the request and annotation boolean async = Boolean.parseBoolean(request.getParameter("async")); @@ -81,6 +81,12 @@ public class AutoJobAspect { "AutoJobAspect caught exception during job execution: {}", ex.getMessage(), ex); + // Rethrow RuntimeException as-is to preserve exception type + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + // Wrap checked exceptions - GlobalExceptionHandler will unwrap + // BaseAppException throw new RuntimeException(ex); } }, @@ -109,7 +115,8 @@ public class AutoJobAspect { int maxRetries, boolean trackProgress, boolean queueable, - int resourceWeight) { + int resourceWeight) + throws Exception { // Keep jobId reference for progress tracking in TaskManager AtomicReference jobIdRef = new AtomicReference<>(); @@ -207,6 +214,12 @@ public class AutoJobAspect { // If we get here, all retries failed if (lastException != null) { + // Rethrow RuntimeException as-is to preserve exception type + if (lastException instanceof RuntimeException) { + throw (RuntimeException) lastException; + } + // Wrap checked exceptions - GlobalExceptionHandler will unwrap + // BaseAppException throw new RuntimeException( "Job failed after " + maxRetries diff --git a/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java b/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java index 1e9d67269..efc42046d 100644 --- a/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java +++ b/app/common/src/main/java/stirling/software/common/configuration/AppConfig.java @@ -76,7 +76,7 @@ public class AppConfig { @Bean(name = "loginEnabled") public boolean loginEnabled() { - return applicationProperties.getSecurity().getEnableLogin(); + return applicationProperties.getSecurity().isEnableLogin(); } @Bean(name = "appName") @@ -120,9 +120,7 @@ public class AppConfig { @Bean(name = "enableAlphaFunctionality") public boolean enableAlphaFunctionality() { - return applicationProperties.getSystem().getEnableAlphaFunctionality() != null - ? applicationProperties.getSystem().getEnableAlphaFunctionality() - : false; + return applicationProperties.getSystem().isEnableAlphaFunctionality(); } @Bean(name = "rateLimit") @@ -265,9 +263,14 @@ public class AppConfig { return "NORMAL"; } - @Bean(name = "disablePixel") - public boolean disablePixel() { - return Boolean.parseBoolean(env.getProperty("DISABLE_PIXEL", "false")); + @Bean(name = "scarfEnabled") + public boolean scarfEnabled() { + return applicationProperties.getSystem().isScarfEnabled(); + } + + @Bean(name = "posthogEnabled") + public boolean posthogEnabled() { + return applicationProperties.getSystem().isPosthogEnabled(); } @Bean(name = "machineType") diff --git a/app/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java b/app/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java index db00c6960..cc5401f86 100644 --- a/app/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java +++ b/app/common/src/main/java/stirling/software/common/configuration/InstallationPathConfig.java @@ -2,6 +2,7 @@ package stirling.software.common.configuration; import java.io.File; import java.nio.file.Paths; +import java.util.Locale; import lombok.extern.slf4j.Slf4j; @@ -61,7 +62,7 @@ public class InstallationPathConfig { private static String initializeBasePath() { if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) { - String os = System.getProperty("os.name").toLowerCase(); + String os = System.getProperty("os.name").toLowerCase(Locale.ROOT); if (os.contains("win")) { return Paths.get( System.getenv("APPDATA"), // parent path diff --git a/app/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java b/app/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java index 53fa97c25..7e6da0f0f 100644 --- a/app/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java +++ b/app/common/src/main/java/stirling/software/common/configuration/RuntimePathConfig.java @@ -10,8 +10,10 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import stirling.software.common.model.ApplicationProperties; +import stirling.software.common.model.ApplicationProperties.CustomPaths; import stirling.software.common.model.ApplicationProperties.CustomPaths.Operations; import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline; +import stirling.software.common.model.ApplicationProperties.System; @Slf4j @Configuration @@ -19,8 +21,16 @@ import stirling.software.common.model.ApplicationProperties.CustomPaths.Pipeline public class RuntimePathConfig { private final ApplicationProperties properties; private final String basePath; + + // Operation paths private final String weasyPrintPath; private final String unoConvertPath; + private final String calibrePath; + private final String ocrMyPdfPath; + private final String sOfficePath; + + // Tesseract data path + private final String tessDataPath; // Pipeline paths private final String pipelineWatchedFoldersPath; @@ -37,7 +47,10 @@ public class RuntimePathConfig { String defaultFinishedFolders = Path.of(this.pipelinePath, "finishedFolders").toString(); String defaultWebUIConfigs = Path.of(this.pipelinePath, "defaultWebUIConfigs").toString(); - Pipeline pipeline = properties.getSystem().getCustomPaths().getPipeline(); + System system = properties.getSystem(); + CustomPaths customPaths = system.getCustomPaths(); + + Pipeline pipeline = customPaths.getPipeline(); this.pipelineWatchedFoldersPath = resolvePath( @@ -57,8 +70,11 @@ public class RuntimePathConfig { // Initialize Operation paths String defaultWeasyPrintPath = isDocker ? "/opt/venv/bin/weasyprint" : "weasyprint"; String defaultUnoConvertPath = isDocker ? "/opt/venv/bin/unoconvert" : "unoconvert"; + String defaultCalibrePath = isDocker ? "/opt/calibre/ebook-convert" : "ebook-convert"; + String defaultOcrMyPdfPath = isDocker ? "/usr/bin/ocrmypdf" : "ocrmypdf"; + String defaultSOfficePath = isDocker ? "/usr/bin/soffice" : "soffice"; - Operations operations = properties.getSystem().getCustomPaths().getOperations(); + Operations operations = customPaths.getOperations(); this.weasyPrintPath = resolvePath( defaultWeasyPrintPath, @@ -67,6 +83,28 @@ public class RuntimePathConfig { resolvePath( defaultUnoConvertPath, operations != null ? operations.getUnoconvert() : null); + this.calibrePath = + resolvePath( + defaultCalibrePath, operations != null ? operations.getCalibre() : null); + this.ocrMyPdfPath = + resolvePath( + defaultOcrMyPdfPath, operations != null ? operations.getOcrmypdf() : null); + this.sOfficePath = + resolvePath( + defaultSOfficePath, operations != null ? operations.getSoffice() : null); + + // Initialize Tesseract data path + String defaultTessDataPath = + isDocker ? "/usr/share/tesseract-ocr/5/tessdata" : "/usr/share/tessdata"; + + String tessPath = system.getTessdataDir(); + String tessdataDir = java.lang.System.getenv("TESSDATA_PREFIX"); + + this.tessDataPath = + resolvePath( + defaultTessDataPath, + (tessPath != null && !tessPath.isEmpty()) ? tessPath : tessdataDir); + log.info("Using Tesseract data path: {}", this.tessDataPath); } private String resolvePath(String defaultPath, String customPath) { diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index 72cfef1a0..2453b2b8b 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Locale; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -152,7 +153,7 @@ public class ApplicationProperties { @Data public static class Security { - private Boolean enableLogin; + private boolean enableLogin; private InitialLogin initialLogin = new InitialLogin(); private OAUTH2 oauth2 = new OAUTH2(); private SAML2 saml2 = new SAML2(); @@ -327,7 +328,7 @@ public class ApplicationProperties { private KeycloakProvider keycloak = new KeycloakProvider(); public Provider get(String registrationId) throws UnsupportedProviderException { - return switch (registrationId.toLowerCase()) { + return switch (registrationId.toLowerCase(Locale.ROOT)) { case "google" -> getGoogle(); case "github" -> getGithub(); case "keycloak" -> getKeycloak(); @@ -335,8 +336,8 @@ public class ApplicationProperties { throw new UnsupportedProviderException( "Logout from the provider " + registrationId - + " is not supported. " - + "Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues"); + + " is not supported. Report it at" + + " https://github.com/Stirling-Tools/Stirling-PDF/issues"); }; } } @@ -389,20 +390,20 @@ public class ApplicationProperties { @Data public static class System { private String defaultLocale; - private Boolean googlevisibility; + private boolean googlevisibility; private boolean showUpdate; - private Boolean showUpdateOnlyAdmin; + private boolean showUpdateOnlyAdmin; private boolean customHTMLFiles; private String tessdataDir; - private Boolean enableAlphaFunctionality; + private boolean enableAlphaFunctionality; private Boolean enableAnalytics; private Boolean enablePosthog; private Boolean enableScarf; private Boolean enableDesktopInstallSlide; private Datasource datasource; - private Boolean disableSanitize; + private boolean disableSanitize; private int maxDPI; - private Boolean enableUrlToPDF; + private boolean enableUrlToPDF; private Html html = new Html(); private CustomPaths customPaths = new CustomPaths(); private String fileUploadLimit; @@ -454,6 +455,9 @@ public class ApplicationProperties { public static class Operations { private String weasyprint; private String unoconvert; + private String calibre; + private String ocrmypdf; + private String soffice; } } @@ -536,10 +540,10 @@ public class ApplicationProperties { @Override public String toString() { return """ - Driver { - driverName='%s' - } - """ + Driver { + driverName='%s' + } + """ .formatted(driverName); } } @@ -571,7 +575,7 @@ public class ApplicationProperties { @Data public static class Metrics { - private Boolean enabled; + private boolean enabled; } @Data @@ -668,6 +672,25 @@ public class ApplicationProperties { public static class EnterpriseFeatures { private PersistentMetrics persistentMetrics = new PersistentMetrics(); private Audit audit = new Audit(); + private DatabaseNotifications databaseNotifications = new DatabaseNotifications(); + + @Data + public static class DatabaseNotifications { + private Backup backups = new Backup(); + private Imports imports = new Imports(); + + @Data + public static class Backup { + private boolean successful = false; + private boolean failed = false; + } + + @Data + public static class Imports { + private boolean successful = false; + private boolean failed = false; + } + } @Data public static class Audit { @@ -702,6 +725,7 @@ public class ApplicationProperties { private int tesseractSessionLimit; private int ghostscriptSessionLimit; private int ocrMyPdfSessionLimit; + private int ffmpegSessionLimit; public int getQpdfSessionLimit() { return qpdfSessionLimit > 0 ? qpdfSessionLimit : 2; @@ -746,6 +770,10 @@ public class ApplicationProperties { public int getOcrMyPdfSessionLimit() { return ocrMyPdfSessionLimit > 0 ? ocrMyPdfSessionLimit : 2; } + + public int getFfmpegSessionLimit() { + return ffmpegSessionLimit > 0 ? ffmpegSessionLimit : 2; + } } @Data @@ -774,6 +802,7 @@ public class ApplicationProperties { private long qpdfTimeoutMinutes; private long ghostscriptTimeoutMinutes; private long ocrMyPdfTimeoutMinutes; + private long ffmpegTimeoutMinutes; public long getTesseractTimeoutMinutes() { return tesseractTimeoutMinutes > 0 ? tesseractTimeoutMinutes : 30; @@ -818,6 +847,10 @@ public class ApplicationProperties { public long getOcrMyPdfTimeoutMinutes() { return ocrMyPdfTimeoutMinutes > 0 ? ocrMyPdfTimeoutMinutes : 30; } + + public long getFfmpegTimeoutMinutes() { + return ffmpegTimeoutMinutes > 0 ? ffmpegTimeoutMinutes : 30; + } } } } diff --git a/app/common/src/main/java/stirling/software/common/model/FileInfo.java b/app/common/src/main/java/stirling/software/common/model/FileInfo.java index 2e3e59e83..e89420296 100644 --- a/app/common/src/main/java/stirling/software/common/model/FileInfo.java +++ b/app/common/src/main/java/stirling/software/common/model/FileInfo.java @@ -30,11 +30,11 @@ public class FileInfo { // Formats the file size into a human-readable string. public String getFormattedFileSize() { if (fileSize >= 1024 * 1024 * 1024) { - return String.format(Locale.US, "%.2f GB", fileSize / (1024.0 * 1024 * 1024)); + return String.format(Locale.ROOT, "%.2f GB", fileSize / (1024.0 * 1024 * 1024)); } else if (fileSize >= 1024 * 1024) { - return String.format(Locale.US, "%.2f MB", fileSize / (1024.0 * 1024)); + return String.format(Locale.ROOT, "%.2f MB", fileSize / (1024.0 * 1024)); } else if (fileSize >= 1024) { - return String.format(Locale.US, "%.2f KB", fileSize / 1024.0); + return String.format(Locale.ROOT, "%.2f KB", fileSize / 1024.0); } else { return String.format("%d Bytes", fileSize); } diff --git a/app/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java b/app/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java index a7f158539..e7473140e 100644 --- a/app/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java +++ b/app/common/src/main/java/stirling/software/common/service/CustomPDFDocumentFactory.java @@ -7,6 +7,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.Locale; import java.util.concurrent.atomic.AtomicLong; import org.apache.pdfbox.Loader; @@ -249,7 +250,7 @@ public class CustomPDFDocumentFactory { log.debug( "Memory status - Free: {}MB ({}%), Used: {}MB, Max: {}MB", actualFreeMemory / (1024 * 1024), - String.format("%.2f", freeMemoryPercent), + String.format(Locale.ROOT, "%.2f", freeMemoryPercent), usedMemory / (1024 * 1024), maxMemory / (1024 * 1024)); @@ -258,7 +259,7 @@ public class CustomPDFDocumentFactory { || actualFreeMemory < MIN_FREE_MEMORY_BYTES) { log.debug( "Low memory detected ({}%), forcing file-based cache", - String.format("%.2f", freeMemoryPercent)); + String.format(Locale.ROOT, "%.2f", freeMemoryPercent)); return createScratchFileCacheFunction(MemoryUsageSetting.setupTempFileOnly()); } else if (contentSize < SMALL_FILE_THRESHOLD) { log.debug("Using memory-only cache for small document ({}KB)", contentSize / 1024); @@ -477,11 +478,6 @@ public class CustomPDFDocumentFactory { return file; } - /** Create a uniquely named temporary directory */ - private Path createTempDirectory(String prefix) throws IOException { - return Files.createTempDirectory(prefix + tempCounter.incrementAndGet() + "-"); - } - /** Create new document bytes based on an existing document */ public byte[] createNewBytesBasedOnOldDocument(byte[] oldDocument) throws IOException { try (PDDocument document = load(oldDocument)) { diff --git a/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java b/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java index 5f3468a18..3dc434423 100644 --- a/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java +++ b/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java @@ -253,6 +253,22 @@ public class JobExecutorService { log.error("Synchronous job timed out after {} ms", timeoutToUse); return ResponseEntity.internalServerError() .body(Map.of("error", "Job timed out after " + timeoutToUse + " ms")); + } catch (RuntimeException e) { + // Check if this is a wrapped typed exception that should be handled by + // GlobalExceptionHandler + Throwable cause = e.getCause(); + if (cause instanceof stirling.software.common.util.ExceptionUtils.BaseAppException + || cause + instanceof + stirling.software.common.util.ExceptionUtils + .BaseValidationException) { + // Rethrow so GlobalExceptionHandler can handle with proper HTTP status codes + throw e; + } + // Handle other RuntimeExceptions as generic errors + log.error("Error executing synchronous job: {}", e.getMessage(), e); + return ResponseEntity.internalServerError() + .body(Map.of("error", "Job failed: " + e.getMessage())); } catch (Exception e) { log.error("Error executing synchronous job: {}", e.getMessage(), e); // Construct a JSON error response diff --git a/app/common/src/main/java/stirling/software/common/service/PostHogService.java b/app/common/src/main/java/stirling/software/common/service/PostHogService.java index 786c04a43..1ec3e8794 100644 --- a/app/common/src/main/java/stirling/software/common/service/PostHogService.java +++ b/app/common/src/main/java/stirling/software/common/service/PostHogService.java @@ -253,7 +253,7 @@ public class PostHogService { addIfNotEmpty( properties, "security_enableLogin", - applicationProperties.getSecurity().getEnableLogin()); + applicationProperties.getSecurity().isEnableLogin()); addIfNotEmpty(properties, "security_csrfDisabled", true); addIfNotEmpty( properties, @@ -299,13 +299,13 @@ public class PostHogService { addIfNotEmpty( properties, "system_googlevisibility", - applicationProperties.getSystem().getGooglevisibility()); + applicationProperties.getSystem().isGooglevisibility()); addIfNotEmpty( properties, "system_showUpdate", applicationProperties.getSystem().isShowUpdate()); addIfNotEmpty( properties, "system_showUpdateOnlyAdmin", - applicationProperties.getSystem().getShowUpdateOnlyAdmin()); + applicationProperties.getSystem().isShowUpdateOnlyAdmin()); addIfNotEmpty( properties, "system_customHTMLFiles", @@ -317,7 +317,7 @@ public class PostHogService { addIfNotEmpty( properties, "system_enableAlphaFunctionality", - applicationProperties.getSystem().getEnableAlphaFunctionality()); + applicationProperties.getSystem().isEnableAlphaFunctionality()); addIfNotEmpty( properties, "system_enableAnalytics", @@ -337,7 +337,7 @@ public class PostHogService { // Capture Metrics properties addIfNotEmpty( - properties, "metrics_enabled", applicationProperties.getMetrics().getEnabled()); + properties, "metrics_enabled", applicationProperties.getMetrics().isEnabled()); // Capture EnterpriseEdition properties addIfNotEmpty( diff --git a/app/common/src/main/java/stirling/software/common/service/ResourceMonitor.java b/app/common/src/main/java/stirling/software/common/service/ResourceMonitor.java index 0e8073d8f..b22923959 100644 --- a/app/common/src/main/java/stirling/software/common/service/ResourceMonitor.java +++ b/app/common/src/main/java/stirling/software/common/service/ResourceMonitor.java @@ -5,6 +5,7 @@ import java.lang.management.MemoryMXBean; import java.lang.management.OperatingSystemMXBean; import java.time.Duration; import java.time.Instant; +import java.util.Locale; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -173,8 +174,8 @@ public class ResourceMonitor { log.info("System resource status changed from {} to {}", oldStatus, newStatus); log.info( "Current metrics - CPU: {}%, Memory: {}%, Free Memory: {} MB", - String.format("%.1f", cpuUsage * 100), - String.format("%.1f", memoryUsage * 100), + String.format(Locale.ROOT, "%.1f", cpuUsage * 100), + String.format(Locale.ROOT, "%.1f", memoryUsage * 100), freeMemory / (1024 * 1024)); } } catch (Exception e) { diff --git a/app/common/src/main/java/stirling/software/common/service/SsrfProtectionService.java b/app/common/src/main/java/stirling/software/common/service/SsrfProtectionService.java index 1f81fb4d4..ce19ff826 100644 --- a/app/common/src/main/java/stirling/software/common/service/SsrfProtectionService.java +++ b/app/common/src/main/java/stirling/software/common/service/SsrfProtectionService.java @@ -5,6 +5,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.URI; import java.net.UnknownHostException; +import java.util.Locale; import java.util.regex.Pattern; import org.springframework.stereotype.Service; @@ -83,7 +84,7 @@ public class SsrfProtectionService { return false; } - return config.getAllowedDomains().contains(host.toLowerCase()); + return config.getAllowedDomains().contains(host.toLowerCase(Locale.ROOT)); } catch (Exception e) { log.debug("Failed to parse URL for MAX security check: {}", url, e); @@ -101,7 +102,7 @@ public class SsrfProtectionService { return false; } - String hostLower = host.toLowerCase(); + String hostLower = host.toLowerCase(Locale.ROOT); // Check explicit blocked domains if (config.getBlockedDomains().contains(hostLower)) { @@ -111,7 +112,7 @@ public class SsrfProtectionService { // Check internal TLD patterns for (String tld : config.getInternalTlds()) { - if (hostLower.endsWith(tld.toLowerCase())) { + if (hostLower.endsWith(tld.toLowerCase(Locale.ROOT))) { log.debug("URL blocked by internal TLD pattern '{}': {}", tld, url); return false; } @@ -123,9 +124,11 @@ public class SsrfProtectionService { config.getAllowedDomains().stream() .anyMatch( domain -> - hostLower.equals(domain.toLowerCase()) + hostLower.equals(domain.toLowerCase(Locale.ROOT)) || hostLower.endsWith( - "." + domain.toLowerCase())); + "." + + domain.toLowerCase( + Locale.ROOT))); if (!isAllowed) { log.debug("URL not in allowed domains list: {}", url); diff --git a/app/common/src/main/java/stirling/software/common/service/TaskManager.java b/app/common/src/main/java/stirling/software/common/service/TaskManager.java index 902b2bfd1..5d2a9edca 100644 --- a/app/common/src/main/java/stirling/software/common/service/TaskManager.java +++ b/app/common/src/main/java/stirling/software/common/service/TaskManager.java @@ -7,6 +7,7 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; @@ -101,14 +102,16 @@ public class TaskManager { if (!extractedFiles.isEmpty()) { jobResult.completeWithFiles(extractedFiles); log.debug( - "Set multiple file results for job ID: {} with {} files extracted from ZIP", + "Set multiple file results for job ID: {} with {} files extracted from" + + " ZIP", jobId, extractedFiles.size()); return; } } catch (Exception e) { log.warn( - "Failed to extract ZIP file for job {}: {}. Falling back to single file result.", + "Failed to extract ZIP file for job {}: {}. Falling back to single file" + + " result.", jobId, e.getMessage()); } @@ -342,12 +345,12 @@ public class TaskManager { /** Check if a file is a ZIP file based on content type and filename */ private boolean isZipFile(String contentType, String fileName) { if (contentType != null - && (contentType.equals("application/zip") - || contentType.equals("application/x-zip-compressed"))) { + && ("application/zip".equals(contentType) + || "application/x-zip-compressed".equals(contentType))) { return true; } - if (fileName != null && fileName.toLowerCase().endsWith(".zip")) { + if (fileName != null && fileName.toLowerCase(Locale.ROOT).endsWith(".zip")) { return true; } @@ -414,7 +417,7 @@ public class TaskManager { return MediaType.APPLICATION_OCTET_STREAM_VALUE; } - String lowerName = fileName.toLowerCase(); + String lowerName = fileName.toLowerCase(Locale.ROOT); if (lowerName.endsWith(".pdf")) { return MediaType.APPLICATION_PDF_VALUE; } else if (lowerName.endsWith(".txt")) { diff --git a/app/common/src/main/java/stirling/software/common/util/CbrUtils.java b/app/common/src/main/java/stirling/software/common/util/CbrUtils.java index 429d22407..c6f9ea78f 100644 --- a/app/common/src/main/java/stirling/software/common/util/CbrUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/CbrUtils.java @@ -6,6 +6,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Locale; import org.apache.commons.io.FilenameUtils; import org.apache.pdfbox.pdmodel.PDDocument; @@ -58,31 +59,24 @@ public class CbrUtils { log.warn( "Failed to open CBR/RAR archive due to corrupt header: {}", e.getMessage()); - throw ExceptionUtils.createIllegalArgumentException( - "error.invalidFormat", - "Invalid or corrupted CBR/RAR archive. " - + "The file may be corrupted, use an unsupported RAR format (RAR5+), " - + "or may not be a valid RAR archive. " - + "Please ensure the file is a valid RAR archive."); + throw ExceptionUtils.createCbrInvalidFormatException(null); } catch (RarException e) { log.warn("Failed to open CBR/RAR archive: {}", e.getMessage()); - String errorMessage; String exMessage = e.getMessage() != null ? e.getMessage() : ""; if (exMessage.contains("encrypted")) { - errorMessage = "Encrypted CBR/RAR archives are not supported."; + throw ExceptionUtils.createCbrEncryptedException(); } else if (exMessage.isEmpty()) { - errorMessage = - "Invalid CBR/RAR archive. " - + "The file may be encrypted, corrupted, or use an unsupported format."; + throw ExceptionUtils.createCbrInvalidFormatException( + "Invalid CBR/RAR archive. The file may be encrypted, corrupted, or" + + " use an unsupported format."); } else { - errorMessage = + throw ExceptionUtils.createCbrInvalidFormatException( "Invalid CBR/RAR archive: " + exMessage - + ". The file may be encrypted, corrupted, or use an unsupported format."; + + ". The file may be encrypted, corrupted, or use an" + + " unsupported format."); } - throw ExceptionUtils.createIllegalArgumentException( - "error.invalidFormat", errorMessage); } catch (IOException e) { log.warn("IO error reading CBR/RAR archive: {}", e.getMessage()); throw ExceptionUtils.createFileProcessingException("CBR extraction", e); @@ -121,7 +115,8 @@ public class CbrUtils { if (imageEntries.isEmpty()) { throw ExceptionUtils.createIllegalArgumentException( "error.fileProcessing", - "No valid images found in the CBR file. The archive may be empty or contain no supported image formats."); + "No valid images found in the CBR file. The archive may be empty or" + + " contain no supported image formats."); } for (ImageEntryData imageEntry : imageEntries) { @@ -146,7 +141,8 @@ public class CbrUtils { if (document.getNumberOfPages() == 0) { throw ExceptionUtils.createIllegalArgumentException( "error.fileProcessing", - "No images could be processed from the CBR file. All images may be corrupted or in unsupported formats."); + "No images could be processed from the CBR file. All images may be" + + " corrupted or in unsupported formats."); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -159,7 +155,6 @@ public class CbrUtils { return GeneralUtils.optimizePdfWithGhostscript(pdfBytes); } catch (IOException e) { log.warn("Ghostscript optimization failed, returning unoptimized PDF", e); - return pdfBytes; } } @@ -170,17 +165,17 @@ public class CbrUtils { private void validateCbrFile(MultipartFile file) { if (file == null || file.isEmpty()) { - throw new IllegalArgumentException("File cannot be null or empty"); + throw ExceptionUtils.createFileNullOrEmptyException(); } String filename = file.getOriginalFilename(); if (filename == null) { - throw new IllegalArgumentException("File must have a name"); + throw ExceptionUtils.createFileNoNameException(); } - String extension = FilenameUtils.getExtension(filename).toLowerCase(); + String extension = FilenameUtils.getExtension(filename).toLowerCase(Locale.ROOT); if (!"cbr".equals(extension) && !"rar".equals(extension)) { - throw new IllegalArgumentException("File must be a CBR or RAR archive"); + throw ExceptionUtils.createNotCbrFileException(); } } @@ -190,7 +185,7 @@ public class CbrUtils { return false; } - String extension = FilenameUtils.getExtension(filename).toLowerCase(); + String extension = FilenameUtils.getExtension(filename).toLowerCase(Locale.ROOT); return "cbr".equals(extension) || "rar".equals(extension); } diff --git a/app/common/src/main/java/stirling/software/common/util/CbzUtils.java b/app/common/src/main/java/stirling/software/common/util/CbzUtils.java index 5eb620e8e..d9fb40189 100644 --- a/app/common/src/main/java/stirling/software/common/util/CbzUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/CbzUtils.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.Enumeration; import java.util.List; +import java.util.Locale; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; @@ -55,10 +56,10 @@ public class CbzUtils { new java.io.FileInputStream(tempFile.getFile())); ZipInputStream zis = new ZipInputStream(bis)) { if (zis.getNextEntry() == null) { - throw new IllegalArgumentException("Archive is empty or invalid ZIP"); + throw ExceptionUtils.createCbzEmptyException(); } } catch (IOException e) { - throw new IllegalArgumentException("Invalid CBZ/ZIP archive", e); + throw ExceptionUtils.createCbzInvalidFormatException(e); } try (PDDocument document = pdfDocumentFactory.createNewDocument(); @@ -83,7 +84,7 @@ public class CbzUtils { Comparator.comparing(ImageEntryData::name, new NaturalOrderComparator())); if (imageEntries.isEmpty()) { - throw new IllegalArgumentException("No valid images found in the CBZ file"); + throw ExceptionUtils.createCbzNoImagesException(); } for (ImageEntryData imageEntry : imageEntries) { @@ -106,8 +107,7 @@ public class CbzUtils { } if (document.getNumberOfPages() == 0) { - throw new IllegalArgumentException( - "No images could be processed from the CBZ file"); + throw ExceptionUtils.createCbzCorruptedImagesException(); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); document.save(baos); @@ -119,7 +119,6 @@ public class CbzUtils { return GeneralUtils.optimizePdfWithGhostscript(pdfBytes); } catch (IOException e) { log.warn("Ghostscript optimization failed, returning unoptimized PDF", e); - return pdfBytes; } } @@ -130,17 +129,17 @@ public class CbzUtils { private void validateCbzFile(MultipartFile file) { if (file == null || file.isEmpty()) { - throw new IllegalArgumentException("File cannot be null or empty"); + throw ExceptionUtils.createFileNullOrEmptyException(); } String filename = file.getOriginalFilename(); if (filename == null) { - throw new IllegalArgumentException("File must have a name"); + throw ExceptionUtils.createFileNoNameException(); } - String extension = FilenameUtils.getExtension(filename).toLowerCase(); + String extension = FilenameUtils.getExtension(filename).toLowerCase(Locale.ROOT); if (!"cbz".equals(extension) && !"zip".equals(extension)) { - throw new IllegalArgumentException("File must be a CBZ or ZIP archive"); + throw ExceptionUtils.createNotCbzFileException(); } } @@ -150,7 +149,7 @@ public class CbzUtils { return false; } - String extension = FilenameUtils.getExtension(filename).toLowerCase(); + String extension = FilenameUtils.getExtension(filename).toLowerCase(Locale.ROOT); return "cbz".equals(extension) || "zip".equals(extension); } @@ -160,7 +159,7 @@ public class CbzUtils { return false; } - String extension = FilenameUtils.getExtension(filename).toLowerCase(); + String extension = FilenameUtils.getExtension(filename).toLowerCase(Locale.ROOT); return "cbz".equals(extension) || "zip".equals(extension) || "cbr".equals(extension) diff --git a/app/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java b/app/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java index f39daf8ae..0927f8c59 100644 --- a/app/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java +++ b/app/common/src/main/java/stirling/software/common/util/CheckProgramInstall.java @@ -11,6 +11,8 @@ public class CheckProgramInstall { private static final List PYTHON_COMMANDS = Arrays.asList("python3", "python"); private static boolean pythonAvailableChecked = false; private static String availablePythonCommand = null; + private static boolean ffmpegAvailableChecked = false; + private static boolean ffmpegAvailable = false; /** * Checks which Python command is available and returns it. @@ -56,4 +58,25 @@ public class CheckProgramInstall { public static boolean isPythonAvailable() { return getAvailablePythonCommand() != null; } + + /** + * Checks if FFmpeg is available on the system. + * + * @return true if FFmpeg is installed and accessible, false otherwise. + */ + public static boolean isFfmpegAvailable() { + if (!ffmpegAvailableChecked) { + try { + ProcessExecutorResult result = + ProcessExecutor.getInstance(ProcessExecutor.Processes.FFMPEG) + .runCommandWithOutputHandling(Arrays.asList("ffmpeg", "-version")); + ffmpegAvailable = true; + } catch (IOException | InterruptedException e) { + ffmpegAvailable = false; + } finally { + ffmpegAvailableChecked = true; + } + } + return ffmpegAvailable; + } } diff --git a/app/common/src/main/java/stirling/software/common/util/ChecksumUtils.java b/app/common/src/main/java/stirling/software/common/util/ChecksumUtils.java index d9749deea..ab39ca5da 100644 --- a/app/common/src/main/java/stirling/software/common/util/ChecksumUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/ChecksumUtils.java @@ -58,14 +58,11 @@ public class ChecksumUtils { * @throws IOException if reading from the stream fails */ public static String checksum(InputStream is, String algorithm) throws IOException { - switch (algorithm.toUpperCase(Locale.ROOT)) { - case "CRC32": - return checksumChecksum(is, new CRC32()); - case "ADLER32": - return checksumChecksum(is, new Adler32()); - default: - return toHex(checksumBytes(is, algorithm)); - } + return switch (algorithm.toUpperCase(Locale.ROOT)) { + case "CRC32" -> checksumChecksum(is, new CRC32()); + case "ADLER32" -> checksumChecksum(is, new Adler32()); + default -> toHex(checksumBytes(is, algorithm)); + }; } /** @@ -98,14 +95,13 @@ public class ChecksumUtils { * @throws IOException if reading from the stream fails */ public static String checksumBase64(InputStream is, String algorithm) throws IOException { - switch (algorithm.toUpperCase(Locale.ROOT)) { - case "CRC32": - return Base64.getEncoder().encodeToString(checksumChecksumBytes(is, new CRC32())); - case "ADLER32": - return Base64.getEncoder().encodeToString(checksumChecksumBytes(is, new Adler32())); - default: - return Base64.getEncoder().encodeToString(checksumBytes(is, algorithm)); - } + return switch (algorithm.toUpperCase(Locale.ROOT)) { + case "CRC32" -> + Base64.getEncoder().encodeToString(checksumChecksumBytes(is, new CRC32())); + case "ADLER32" -> + Base64.getEncoder().encodeToString(checksumChecksumBytes(is, new Adler32())); + default -> Base64.getEncoder().encodeToString(checksumBytes(is, algorithm)); + }; } /** @@ -179,7 +175,7 @@ public class ChecksumUtils { for (Map.Entry entry : checksums.entrySet()) { // Keep value as long and mask to ensure unsigned hex formatting. long unsigned32 = entry.getValue().getValue() & UNSIGNED_32_BIT_MASK; - results.put(entry.getKey(), String.format("%08x", unsigned32)); + results.put(entry.getKey(), String.format(Locale.ROOT, "%08x", unsigned32)); } return results; } @@ -258,7 +254,7 @@ public class ChecksumUtils { } // Keep as long and mask to ensure correct unsigned representation. long unsigned32 = checksum.getValue() & UNSIGNED_32_BIT_MASK; - return String.format("%08x", unsigned32); + return String.format(Locale.ROOT, "%08x", unsigned32); } /** @@ -294,7 +290,7 @@ public class ChecksumUtils { private static String toHex(byte[] hash) { StringBuilder sb = new StringBuilder(hash.length * 2); for (byte b : hash) { - sb.append(String.format("%02x", b)); + sb.append(String.format(Locale.ROOT, "%02x", b)); } return sb.toString(); } diff --git a/app/common/src/main/java/stirling/software/common/util/CustomHtmlSanitizer.java b/app/common/src/main/java/stirling/software/common/util/CustomHtmlSanitizer.java index c5fb07645..05bb6e546 100644 --- a/app/common/src/main/java/stirling/software/common/util/CustomHtmlSanitizer.java +++ b/app/common/src/main/java/stirling/software/common/util/CustomHtmlSanitizer.java @@ -62,8 +62,7 @@ public class CustomHtmlSanitizer { .and(new HtmlPolicyBuilder().disallowElements("noscript").toFactory()); public String sanitize(String html) { - boolean disableSanitize = - Boolean.TRUE.equals(applicationProperties.getSystem().getDisableSanitize()); + boolean disableSanitize = applicationProperties.getSystem().isDisableSanitize(); return disableSanitize ? html : POLICY.sanitize(html); } } diff --git a/app/common/src/main/java/stirling/software/common/util/EmlParser.java b/app/common/src/main/java/stirling/software/common/util/EmlParser.java index ec71fbb19..642bc3a5e 100644 --- a/app/common/src/main/java/stirling/software/common/util/EmlParser.java +++ b/app/common/src/main/java/stirling/software/common/util/EmlParser.java @@ -11,6 +11,7 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Properties; import java.util.regex.Pattern; @@ -229,7 +230,8 @@ public class EmlParser { Method getContentType = message.getClass().getMethod("getContentType"); String contentType = (String) getContentType.invoke(message); - if (contentType != null && contentType.toLowerCase().contains(TEXT_HTML)) { + if (contentType != null + && contentType.toLowerCase(Locale.ROOT).contains(TEXT_HTML)) { content.setHtmlBody(stringContent); } else { content.setTextBody(stringContent); @@ -296,7 +298,7 @@ public class EmlParser { String contentType = (String) getContentType.invoke(part); String normalizedDisposition = - disposition != null ? ((String) disposition).toLowerCase() : null; + disposition != null ? ((String) disposition).toLowerCase(Locale.ROOT) : null; if ((Boolean) isMimeType.invoke(part, TEXT_PLAIN) && normalizedDisposition == null) { Object partContent = getContent.invoke(part); @@ -422,7 +424,7 @@ public class EmlParser { RegexPatternUtils.getInstance().getNewlineSplitPattern().split(emlContent); for (int i = 0; i < lines.length; i++) { String line = lines[i]; - if (line.toLowerCase().startsWith(headerName.toLowerCase())) { + if (line.toLowerCase(Locale.ROOT).startsWith(headerName.toLowerCase(Locale.ROOT))) { StringBuilder value = new StringBuilder(line.substring(headerName.length()).trim()); for (int j = i + 1; j < lines.length; j++) { @@ -444,7 +446,7 @@ public class EmlParser { private static String extractHtmlBody(String emlContent) { try { - String lowerContent = emlContent.toLowerCase(); + String lowerContent = emlContent.toLowerCase(Locale.ROOT); int htmlStart = lowerContent.indexOf(HEADER_CONTENT_TYPE + " " + TEXT_HTML); if (htmlStart == -1) return null; @@ -463,7 +465,7 @@ public class EmlParser { private static String extractTextBody(String emlContent) { try { - String lowerContent = emlContent.toLowerCase(); + String lowerContent = emlContent.toLowerCase(Locale.ROOT); int textStart = lowerContent.indexOf(HEADER_CONTENT_TYPE + " " + TEXT_PLAIN); if (textStart == -1) { int bodyStart = emlContent.indexOf("\r\n\r\n"); @@ -516,7 +518,7 @@ public class EmlParser { String currentEncoding = ""; for (String line : lines) { - String lowerLine = line.toLowerCase().trim(); + String lowerLine = line.toLowerCase(Locale.ROOT).trim(); if (line.trim().isEmpty()) { inHeaders = false; @@ -554,9 +556,12 @@ public class EmlParser { } private static boolean isAttachment(String disposition, String filename, String contentType) { - return (disposition.toLowerCase().contains(DISPOSITION_ATTACHMENT) && !filename.isEmpty()) - || (!filename.isEmpty() && !contentType.toLowerCase().startsWith("text/")) - || (contentType.toLowerCase().contains("application/") && !filename.isEmpty()); + return (disposition.toLowerCase(Locale.ROOT).contains(DISPOSITION_ATTACHMENT) + && !filename.isEmpty()) + || (!filename.isEmpty() + && !contentType.toLowerCase(Locale.ROOT).startsWith("text/")) + || (contentType.toLowerCase(Locale.ROOT).contains("application/") + && !filename.isEmpty()); } private static String extractFilenameFromDisposition(String disposition) { @@ -565,8 +570,8 @@ public class EmlParser { } // Handle filename*= (RFC 2231 encoded filename) - if (disposition.toLowerCase().contains("filename*=")) { - int filenameStarStart = disposition.toLowerCase().indexOf("filename*=") + 10; + if (disposition.toLowerCase(Locale.ROOT).contains("filename*=")) { + int filenameStarStart = disposition.toLowerCase(Locale.ROOT).indexOf("filename*=") + 10; int filenameStarEnd = disposition.indexOf(";", filenameStarStart); if (filenameStarEnd == -1) filenameStarEnd = disposition.length(); String extendedFilename = @@ -586,7 +591,7 @@ public class EmlParser { } // Handle regular filename= - int filenameStart = disposition.toLowerCase().indexOf("filename=") + 9; + int filenameStart = disposition.toLowerCase(Locale.ROOT).indexOf("filename=") + 9; int filenameEnd = disposition.indexOf(";", filenameStart); if (filenameEnd == -1) filenameEnd = disposition.length(); String filename = disposition.substring(filenameStart, filenameEnd).trim(); diff --git a/app/common/src/main/java/stirling/software/common/util/EmlProcessingUtils.java b/app/common/src/main/java/stirling/software/common/util/EmlProcessingUtils.java index 55035fe9f..69b181161 100644 --- a/app/common/src/main/java/stirling/software/common/util/EmlProcessingUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/EmlProcessingUtils.java @@ -48,11 +48,11 @@ public class EmlProcessingUtils { public static void validateEmlInput(byte[] emlBytes) { if (emlBytes == null || emlBytes.length == 0) { - throw new IllegalArgumentException("EML file is empty or null"); + throw ExceptionUtils.createEmlEmptyException(); } if (isInvalidEmlFormat(emlBytes)) { - throw new IllegalArgumentException("Invalid EML file format"); + throw ExceptionUtils.createEmlInvalidFormatException(); } } @@ -109,12 +109,13 @@ public class EmlProcessingUtils { html.append( String.format( + Locale.ROOT, """ - - - %s -