From 8c01425eeed94ae40b4903183ae75eb6af4be8a6 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:42:38 +0100 Subject: [PATCH] Lots of changes (#1889) * Add image support to multi-tool page Related to #278 * changes to support image types * final touches * final touches * final touches Signed-off-by: a * final touches Signed-off-by: a * final touches Signed-off-by: a * final touches Signed-off-by: a * final touches Signed-off-by: a * final touches Signed-off-by: a * final touches Signed-off-by: a * Update translation files (#1888) Signed-off-by: GitHub Action Co-authored-by: GitHub Action --------- Signed-off-by: a Signed-off-by: GitHub Action Co-authored-by: a Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: GitHub Action --- .../docker-compose-latest-fat-security.yml | 1 - ...ocker-compose-latest-security-with-sso.yml | 1 - .../docker-compose-latest-security.yml | 1 - ...ker-compose-latest-ultra-lite-security.yml | 1 - .../docker-compose-latest-ultra-lite.yml | 1 - exampleYmlFiles/docker-compose-latest.yml | 1 - .../software/SPDF/EE/EEAppConfig.java | 25 + .../software/SPDF/SPdfApplication.java | 1 - .../software/SPDF/config/AppConfig.java | 25 + .../SPDF/config/AppUpdateService.java | 2 +- .../software/SPDF/config/MetricsFilter.java | 23 +- .../SPDF/config/PdfMetadataService.java | 139 +++++ .../config/security/AppUpdateAuthService.java | 2 +- .../security/SecurityConfiguration.java | 14 +- .../security/UserAuthenticationFilter.java | 5 +- .../SPDF/config/security/UserService.java | 11 + ...tomOAuth2AuthenticationSuccessHandler.java | 2 +- .../CustomOAuth2LogoutSuccessHandler.java | 2 +- .../oauth2/CustomOAuth2UserService.java | 2 +- .../controller/api/SplitPDFController.java | 6 +- .../api/SplitPdfByChaptersController.java | 6 +- .../SPDF/controller/api/UserController.java | 4 +- .../api/misc/FlattenController.java | 6 +- .../controller/api/misc/ShowJavascript.java | 4 +- .../api/pipeline/UserServiceInterface.java | 2 + .../controller/web/AccountWebController.java | 6 +- .../controller/web/MetricsController.java | 351 ++++++----- .../SPDF/model/ApplicationProperties.java | 557 +++--------------- .../SPDF/repository/UserRepository.java | 1 - .../software/SPDF/utils/PdfUtils.java | 27 - .../software/SPDF/utils/RequestUriUtils.java | 23 + src/main/resources/messages_ar_AR.properties | 6 +- src/main/resources/messages_bg_BG.properties | 6 +- src/main/resources/messages_ca_CA.properties | 6 +- src/main/resources/messages_cs_CZ.properties | 6 +- src/main/resources/messages_da_DK.properties | 6 +- src/main/resources/messages_de_DE.properties | 6 +- src/main/resources/messages_el_GR.properties | 6 +- src/main/resources/messages_en_GB.properties | 6 +- src/main/resources/messages_en_US.properties | 6 +- src/main/resources/messages_es_ES.properties | 6 +- src/main/resources/messages_eu_ES.properties | 6 +- src/main/resources/messages_fr_FR.properties | 6 +- src/main/resources/messages_ga_IE.properties | 6 +- src/main/resources/messages_hi_IN.properties | 6 +- src/main/resources/messages_hr_HR.properties | 6 +- src/main/resources/messages_hu_HU.properties | 6 +- src/main/resources/messages_id_ID.properties | 6 +- src/main/resources/messages_it_IT.properties | 6 +- src/main/resources/messages_ja_JP.properties | 6 +- src/main/resources/messages_ko_KR.properties | 6 +- src/main/resources/messages_nl_NL.properties | 6 +- src/main/resources/messages_no_NB.properties | 6 +- src/main/resources/messages_pl_PL.properties | 6 +- src/main/resources/messages_pt_BR.properties | 6 +- src/main/resources/messages_pt_PT.properties | 6 +- src/main/resources/messages_ro_RO.properties | 6 +- src/main/resources/messages_ru_RU.properties | 6 +- src/main/resources/messages_sk_SK.properties | 6 +- .../resources/messages_sr_LATN_RS.properties | 6 +- src/main/resources/messages_sv_SE.properties | 6 +- src/main/resources/messages_th_TH.properties | 6 +- src/main/resources/messages_tr_TR.properties | 6 +- src/main/resources/messages_uk_UA.properties | 6 +- src/main/resources/messages_vi_VN.properties | 6 +- src/main/resources/messages_zh_CN.properties | 6 +- src/main/resources/messages_zh_TW.properties | 6 +- src/main/resources/settings.yml.template | 16 + .../static/js/multitool/PdfContainer.js | 2 +- .../resources/templates/fragments/common.html | 16 +- .../resources/templates/fragments/footer.html | 5 + .../templates/misc/add-page-numbers.html | 5 +- src/main/resources/templates/multi-tool.html | 2 +- .../software/SPDF/utils/PdfUtilsTest.java | 7 - 74 files changed, 749 insertions(+), 772 deletions(-) create mode 100644 src/main/java/stirling/software/SPDF/EE/EEAppConfig.java create mode 100644 src/main/java/stirling/software/SPDF/config/PdfMetadataService.java diff --git a/exampleYmlFiles/docker-compose-latest-fat-security.yml b/exampleYmlFiles/docker-compose-latest-fat-security.yml index a581fa9b..f29a8a9f 100644 --- a/exampleYmlFiles/docker-compose-latest-fat-security.yml +++ b/exampleYmlFiles/docker-compose-latest-fat-security.yml @@ -1,4 +1,3 @@ -version: '3.3' services: stirling-pdf: container_name: Stirling-PDF-Security-Fat diff --git a/exampleYmlFiles/docker-compose-latest-security-with-sso.yml b/exampleYmlFiles/docker-compose-latest-security-with-sso.yml index 1970a079..7791ae7a 100644 --- a/exampleYmlFiles/docker-compose-latest-security-with-sso.yml +++ b/exampleYmlFiles/docker-compose-latest-security-with-sso.yml @@ -1,4 +1,3 @@ -version: '3.3' services: stirling-pdf: container_name: Stirling-PDF-Security diff --git a/exampleYmlFiles/docker-compose-latest-security.yml b/exampleYmlFiles/docker-compose-latest-security.yml index b0ec6ea1..c1e8e712 100644 --- a/exampleYmlFiles/docker-compose-latest-security.yml +++ b/exampleYmlFiles/docker-compose-latest-security.yml @@ -1,4 +1,3 @@ -version: '3.3' services: stirling-pdf: container_name: Stirling-PDF-Security diff --git a/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml b/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml index 2faac865..d20ed21c 100644 --- a/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml +++ b/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml @@ -1,4 +1,3 @@ -version: '3.3' services: stirling-pdf: container_name: Stirling-PDF-Ultra-Lite-Security diff --git a/exampleYmlFiles/docker-compose-latest-ultra-lite.yml b/exampleYmlFiles/docker-compose-latest-ultra-lite.yml index da868ff2..990ba959 100644 --- a/exampleYmlFiles/docker-compose-latest-ultra-lite.yml +++ b/exampleYmlFiles/docker-compose-latest-ultra-lite.yml @@ -1,4 +1,3 @@ -version: '3.3' services: stirling-pdf: container_name: Stirling-PDF-Ultra-Lite diff --git a/exampleYmlFiles/docker-compose-latest.yml b/exampleYmlFiles/docker-compose-latest.yml index 6090e291..cab8c3cd 100644 --- a/exampleYmlFiles/docker-compose-latest.yml +++ b/exampleYmlFiles/docker-compose-latest.yml @@ -1,4 +1,3 @@ -version: '3.3' services: stirling-pdf: container_name: Stirling-PDF diff --git a/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java b/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java new file mode 100644 index 00000000..0818aa7d --- /dev/null +++ b/src/main/java/stirling/software/SPDF/EE/EEAppConfig.java @@ -0,0 +1,25 @@ +package stirling.software.SPDF.EE; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +import stirling.software.SPDF.model.ApplicationProperties; + +@Configuration +@Lazy +public class EEAppConfig { + + private static final Logger logger = LoggerFactory.getLogger(EEAppConfig.class); + + @Autowired ApplicationProperties applicationProperties; + + @Bean(name = "RunningEE") + public boolean runningEnterpriseEdition() { + // TODO: Implement EE detection + return false; + } +} diff --git a/src/main/java/stirling/software/SPDF/SPdfApplication.java b/src/main/java/stirling/software/SPDF/SPdfApplication.java index bc17e0f1..6c90ee3c 100644 --- a/src/main/java/stirling/software/SPDF/SPdfApplication.java +++ b/src/main/java/stirling/software/SPDF/SPdfApplication.java @@ -31,7 +31,6 @@ public class SPdfApplication { @Autowired private Environment env; - @Autowired ApplicationProperties applicationProperties; private static String serverPortStatic; diff --git a/src/main/java/stirling/software/SPDF/config/AppConfig.java b/src/main/java/stirling/software/SPDF/config/AppConfig.java index ffa56c19..6fc09917 100644 --- a/src/main/java/stirling/software/SPDF/config/AppConfig.java +++ b/src/main/java/stirling/software/SPDF/config/AppConfig.java @@ -135,4 +135,29 @@ public class AppConfig { } }; } + + @Bean(name = "termsAndConditions") + public String termsAndConditions() { + return applicationProperties.getLegal().getTermsAndConditions(); + } + + @Bean(name = "privacyPolicy") + public String privacyPolicy() { + return applicationProperties.getLegal().getPrivacyPolicy(); + } + + @Bean(name = "cookiePolicy") + public String cookiePolicy() { + return applicationProperties.getLegal().getCookiePolicy(); + } + + @Bean(name = "impressum") + public String impressum() { + return applicationProperties.getLegal().getImpressum(); + } + + @Bean(name = "accessibilityStatement") + public String accessibilityStatement() { + return applicationProperties.getLegal().getAccessibilityStatement(); + } } diff --git a/src/main/java/stirling/software/SPDF/config/AppUpdateService.java b/src/main/java/stirling/software/SPDF/config/AppUpdateService.java index 7c7a9a49..7fc87629 100644 --- a/src/main/java/stirling/software/SPDF/config/AppUpdateService.java +++ b/src/main/java/stirling/software/SPDF/config/AppUpdateService.java @@ -18,7 +18,7 @@ class AppUpdateService { @Bean(name = "shouldShow") @Scope("request") public boolean shouldShow() { - boolean showUpdate = applicationProperties.getSystem().getShowUpdate(); + boolean showUpdate = applicationProperties.getSystem().isShowUpdate(); boolean showAdminResult = (showAdmin != null) ? showAdmin.getShowUpdateOnlyAdmins() : true; return showUpdate && showAdminResult; } diff --git a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java index 876613f4..c0231ca7 100644 --- a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java +++ b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java @@ -13,6 +13,7 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import stirling.software.SPDF.utils.RequestUriUtils; @Component public class MetricsFilter extends OncePerRequestFilter { @@ -30,32 +31,16 @@ public class MetricsFilter extends OncePerRequestFilter { throws ServletException, IOException { String uri = request.getRequestURI(); - // System.out.println("uri="+uri + ", method=" + request.getMethod() ); - // Ignore static resources - if (!(uri.startsWith("/js") - || uri.startsWith("/v1/api-docs") - || uri.endsWith("robots.txt") - || uri.startsWith("/images") - || uri.endsWith(".png") - || uri.endsWith(".ico") - || uri.endsWith(".css") - || uri.endsWith(".map") - || uri.endsWith(".svg") - || uri.endsWith(".js") - || uri.contains("swagger") - || uri.startsWith("/api/v1/info") - || uri.startsWith("/site.webmanifest") - || uri.startsWith("/fonts") - || uri.startsWith("/pdfjs"))) { + if (RequestUriUtils.isTrackableResource(request.getContextPath(), uri)) { Counter counter = Counter.builder("http.requests") - .tag("uri", uri) + .tag("session", request.getSession().getId()) .tag("method", request.getMethod()) + .tag("uri", uri) .register(meterRegistry); counter.increment(); - // System.out.println("Counted"); } filterChain.doFilter(request, response); diff --git a/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java b/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java new file mode 100644 index 00000000..9eba472e --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java @@ -0,0 +1,139 @@ +package stirling.software.SPDF.config; + +import java.util.Calendar; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import jakarta.annotation.PostConstruct; +import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.PdfMetadata; + +@Service +public class PdfMetadataService { + + private static PdfMetadataService instance; + + private final ApplicationProperties applicationProperties; + private final String appVersion; + private final UserServiceInterface userService; + + @Autowired + public PdfMetadataService( + ApplicationProperties applicationProperties, + @Qualifier("appVersion") String appVersion, + @Autowired(required = false) UserServiceInterface userService) { + this.applicationProperties = applicationProperties; + this.appVersion = appVersion; + this.userService = userService; + } + + @PostConstruct + public void init() { + instance = this; + } + + // Static methods for easy access + + public static PdfMetadata extractMetadataFromPdf(PDDocument pdf) { + return instance.extractMetadataFromPdfInstance(pdf); + } + + public static void setDefaultMetadata(PDDocument pdf) { + instance.setDefaultMetadataInstance(pdf); + } + + public static void setMetadataToPdf(PDDocument pdf, PdfMetadata pdfMetadata) { + instance.setMetadataToPdfInstance(pdf, pdfMetadata); + } + + public static void setMetadataToPdf( + PDDocument pdf, PdfMetadata pdfMetadata, boolean newlyCreated) { + instance.setMetadataToPdfInstance(pdf, pdfMetadata, newlyCreated); + } + + // Instance methods + + private PdfMetadata extractMetadataFromPdfInstance(PDDocument pdf) { + return PdfMetadata.builder() + .author(pdf.getDocumentInformation().getAuthor()) + .producer(pdf.getDocumentInformation().getProducer()) + .title(pdf.getDocumentInformation().getTitle()) + .creator(pdf.getDocumentInformation().getCreator()) + .subject(pdf.getDocumentInformation().getSubject()) + .keywords(pdf.getDocumentInformation().getKeywords()) + .creationDate(pdf.getDocumentInformation().getCreationDate()) + .modificationDate(pdf.getDocumentInformation().getModificationDate()) + .build(); + } + + private void setDefaultMetadataInstance(PDDocument pdf) { + PdfMetadata metadata = extractMetadataFromPdfInstance(pdf); + setMetadataToPdfInstance(pdf, metadata); + } + + private void setMetadataToPdfInstance(PDDocument pdf, PdfMetadata pdfMetadata) { + setMetadataToPdfInstance(pdf, pdfMetadata, true); + } + + private void setMetadataToPdfInstance( + PDDocument pdf, PdfMetadata pdfMetadata, boolean newlyCreated) { + if (newlyCreated || pdfMetadata.getCreationDate() == null) { + setNewDocumentMetadata(pdf, pdfMetadata); + } + setCommonMetadata(pdf, pdfMetadata); + } + + private void setNewDocumentMetadata(PDDocument pdf, PdfMetadata pdfMetadata) { + + String title = pdfMetadata.getTitle(); + String creator = "Stirling-PDF"; + +// if (applicationProperties +// .getEnterpriseEdition() +// .getCustomMetadata() +// .isAutoUpdateMetadata()) { + + // producer = + // + // applicationProperties.getEnterpriseEdition().getCustomMetadata().getProducer(); + // creator = + // applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator(); + // title = applicationProperties.getEnterpriseEdition().getCustomMetadata().getTitle(); + +// if ("{filename}".equals(title)) { +// title = "Filename"; // Replace with actual filename logic +// } else if ("{unchanged}".equals(title)) { +// title = pdfMetadata.getTitle(); // Keep the original title +// } +// } + + pdf.getDocumentInformation().setTitle(title); + pdf.getDocumentInformation().setCreator(creator + " " + appVersion); + pdf.getDocumentInformation().setCreationDate(Calendar.getInstance()); + } + + private void setCommonMetadata(PDDocument pdf, PdfMetadata pdfMetadata) { + String producer = "Stirling-PDF"; + pdf.getDocumentInformation().setProducer(producer + " " + appVersion); + pdf.getDocumentInformation().setSubject(pdfMetadata.getSubject()); + pdf.getDocumentInformation().setKeywords(pdfMetadata.getKeywords()); + pdf.getDocumentInformation().setModificationDate(Calendar.getInstance()); + + String author = pdfMetadata.getAuthor(); + // if (applicationProperties + // .getEnterpriseEdition() + // .getCustomMetadata() + // .isAutoUpdateMetadata()) { + // author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor(); + + // if (userService != null) { + // author = author.replace("username", userService.getCurrentUsername()); + // } + // } + pdf.getDocumentInformation().setAuthor(author); + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java b/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java index c4b53ad5..5a16aa30 100644 --- a/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java +++ b/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java @@ -20,7 +20,7 @@ class AppUpdateAuthService implements ShowAdminInterface { @Override public boolean getShowUpdateOnlyAdmins() { - boolean showUpdate = applicationProperties.getSystem().getShowUpdate(); + boolean showUpdate = applicationProperties.getSystem().isShowUpdate(); if (!showUpdate) { return showUpdate; } diff --git a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java index ed7b7921..aa266d2f 100644 --- a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java @@ -152,8 +152,8 @@ public class SecurityConfiguration { .authenticated()); // Handle OAUTH2 Logins - if (applicationProperties.getSecurity().getOAUTH2() != null - && applicationProperties.getSecurity().getOAUTH2().getEnabled() + if (applicationProperties.getSecurity().getOauth2() != null + && applicationProperties.getSecurity().getOauth2().getEnabled() && !applicationProperties .getSecurity() .getLoginMethod() @@ -222,7 +222,7 @@ public class SecurityConfiguration { } private Optional googleClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); if (oauth == null || !oauth.getEnabled()) { return Optional.empty(); } @@ -251,7 +251,7 @@ public class SecurityConfiguration { } private Optional keycloakClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); if (oauth == null || !oauth.getEnabled()) { return Optional.empty(); } @@ -275,7 +275,7 @@ public class SecurityConfiguration { } private Optional githubClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); if (oauth == null || !oauth.getEnabled()) { return Optional.empty(); } @@ -304,7 +304,7 @@ public class SecurityConfiguration { } private Optional oidcClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); if (oauth == null || oauth.getIssuer() == null || oauth.getIssuer().isEmpty() @@ -352,7 +352,7 @@ public class SecurityConfiguration { String useAsUsername = applicationProperties .getSecurity() - .getOAUTH2() + .getOauth2() .getUseAsUsername(); Optional userOpt = userService.findByUsernameIgnoreCase( diff --git a/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java b/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java index b71fab77..79b28521 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java @@ -159,7 +159,10 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { }; for (String pattern : permitAllPatterns) { - if (uri.startsWith(pattern) || uri.endsWith(".svg") || uri.endsWith(".png") || uri.endsWith(".ico")) { + if (uri.startsWith(pattern) + || uri.endsWith(".svg") + || uri.endsWith(".png") + || uri.endsWith(".ico")) { return true; } } diff --git a/src/main/java/stirling/software/SPDF/config/security/UserService.java b/src/main/java/stirling/software/SPDF/config/security/UserService.java index 5adfdbc7..ece81355 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserService.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserService.java @@ -11,6 +11,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -342,4 +343,14 @@ public class UserService implements UserServiceInterface { } } } + + public String getCurrentUsername() { + Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + if (principal instanceof UserDetails) { + return ((UserDetails) principal).getUsername(); + } else { + return principal.toString(); + } + } } diff --git a/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java b/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java index 4c7e04d9..c8c3f217 100644 --- a/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java +++ b/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2AuthenticationSuccessHandler.java @@ -66,7 +66,7 @@ public class CustomOAuth2AuthenticationSuccessHandler // Redirect to the original destination super.onAuthenticationSuccess(request, response, authentication); } else { - OAUTH2 oAuth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oAuth = applicationProperties.getSecurity().getOauth2(); if (loginAttemptService.isBlocked(username)) { if (session != null) { diff --git a/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2LogoutSuccessHandler.java b/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2LogoutSuccessHandler.java index 907ddd4b..5bbff53f 100644 --- a/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2LogoutSuccessHandler.java +++ b/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2LogoutSuccessHandler.java @@ -43,7 +43,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand } return; } - OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); if (authentication instanceof OAuth2AuthenticationToken) { OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication; diff --git a/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2UserService.java b/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2UserService.java index b9766480..ebe734b5 100644 --- a/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2UserService.java +++ b/src/main/java/stirling/software/SPDF/config/security/oauth2/CustomOAuth2UserService.java @@ -43,7 +43,7 @@ public class CustomOAuth2UserService implements OAuth2UserService pageNumbers = request.getPageNumbersList(document, false); System.out.println( @@ -79,7 +79,7 @@ public class SplitPDFController { previousPageNumber = splitPoint + 1; // Transfer metadata to split pdf - PdfUtils.setMetadataToPdf(splitDocument, metadata); + PdfMetadataService.setMetadataToPdf(splitDocument, metadata); ByteArrayOutputStream baos = new ByteArrayOutputStream(); splitDocument.save(baos); diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java index 776856ec..8d020b16 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java @@ -31,9 +31,9 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import stirling.software.SPDF.config.PdfMetadataService; import stirling.software.SPDF.model.PdfMetadata; import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest; -import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -258,7 +258,7 @@ public class SplitPdfByChaptersController { List splitDocumentsBoas = new ArrayList<>(); PdfMetadata metadata = null; if (includeMetadata) { - metadata = PdfUtils.extractMetadataFromPdf(sourceDocument); + metadata = PdfMetadataService.extractMetadataFromPdf(sourceDocument); } for (Bookmark bookmark : bookmarks) { try (PDDocument splitDocument = new PDDocument()) { @@ -273,7 +273,7 @@ public class SplitPdfByChaptersController { } ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (includeMetadata) { - PdfUtils.setMetadataToPdf(splitDocument, metadata); + PdfMetadataService.setMetadataToPdf(splitDocument, metadata); } splitDocument.save(baos); diff --git a/src/main/java/stirling/software/SPDF/controller/api/UserController.java b/src/main/java/stirling/software/SPDF/controller/api/UserController.java index bc59b91e..719adac1 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/UserController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/UserController.java @@ -208,8 +208,8 @@ public class UserController { @PreAuthorize("hasRole('ROLE_ADMIN')") @PostMapping("/admin/saveUser") public RedirectView saveUser( - @RequestParam String username, - @RequestParam(name = "password", required = false) String password, + @RequestParam(name = "username", required = true) String username, + @RequestParam(name = "password", required = true) String password, @RequestParam(name = "role") String role, @RequestParam(name = "authType") String authType, @RequestParam(name = "forceChange", required = false, defaultValue = "false") diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java index 888d7670..c180fafa 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/misc/FlattenController.java @@ -25,9 +25,9 @@ import io.github.pixee.security.Filenames; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import stirling.software.SPDF.config.PdfMetadataService; import stirling.software.SPDF.model.PdfMetadata; import stirling.software.SPDF.model.api.misc.FlattenRequest; -import stirling.software.SPDF.utils.PdfUtils; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -46,7 +46,7 @@ public class FlattenController { MultipartFile file = request.getFileInput(); PDDocument document = Loader.loadPDF(file.getBytes()); - PdfMetadata metadata = PdfUtils.extractMetadataFromPdf(document); + PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document); Boolean flattenOnlyForms = request.getFlattenOnlyForms(); if (Boolean.TRUE.equals(flattenOnlyForms)) { @@ -80,7 +80,7 @@ public class FlattenController { logger.error("exception", e); } } - PdfUtils.setMetadataToPdf(newDocument, metadata); + PdfMetadataService.setMetadataToPdf(newDocument, metadata); return WebResponseUtils.pdfDocToWebResponse( newDocument, Filenames.toSimpleFileName(file.getOriginalFilename())); } diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java b/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java index 0a93bf1d..a608fde9 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java +++ b/src/main/java/stirling/software/SPDF/controller/api/misc/ShowJavascript.java @@ -9,6 +9,7 @@ import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; @@ -75,7 +76,8 @@ public class ShowJavascript { return WebResponseUtils.bytesToWebResponse( script.getBytes(StandardCharsets.UTF_8), - Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + ".js"); + Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + ".js", + MediaType.TEXT_PLAIN); } } } diff --git a/src/main/java/stirling/software/SPDF/controller/api/pipeline/UserServiceInterface.java b/src/main/java/stirling/software/SPDF/controller/api/pipeline/UserServiceInterface.java index 1a60441e..c3facb35 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/pipeline/UserServiceInterface.java +++ b/src/main/java/stirling/software/SPDF/controller/api/pipeline/UserServiceInterface.java @@ -2,4 +2,6 @@ package stirling.software.SPDF.controller.api.pipeline; public interface UserServiceInterface { String getApiKeyForUser(String username); + + String getCurrentUsername(); } diff --git a/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java b/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java index 2f6b5042..9081164d 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java @@ -51,7 +51,7 @@ public class AccountWebController { Map providerList = new HashMap<>(); - OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); + OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); if (oauth != null) { if (oauth.isSettingsValid()) { providerList.put("oidc", oauth.getProvider()); @@ -82,7 +82,7 @@ public class AccountWebController { model.addAttribute("loginMethod", applicationProperties.getSecurity().getLoginMethod()); model.addAttribute( - "oAuth2Enabled", applicationProperties.getSecurity().getOAUTH2().getEnabled()); + "oAuth2Enabled", applicationProperties.getSecurity().getOauth2().getEnabled()); model.addAttribute("currentPage", "login"); @@ -345,7 +345,7 @@ public class AccountWebController { // Retrieve username and other attributes username = userDetails.getAttribute( - applicationProperties.getSecurity().getOAUTH2().getUseAsUsername()); + applicationProperties.getSecurity().getOauth2().getUseAsUsername()); // Add oAuth2 Login attributes to the model model.addAttribute("oAuth2Login", true); } diff --git a/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java b/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java index 155fcdbd..ff73fb2d 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java @@ -2,11 +2,7 @@ package stirling.software.SPDF.controller.web; import java.time.Duration; import java.time.LocalDateTime; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; @@ -18,19 +14,20 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import io.micrometer.core.instrument.Counter; -import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.StartupApplicationListener; import stirling.software.SPDF.model.ApplicationProperties; @RestController @RequestMapping("/api/v1/info") @Tag(name = "Info", description = "Info APIs") +@Slf4j public class MetricsController { @Autowired ApplicationProperties applicationProperties; @@ -46,6 +43,7 @@ public class MetricsController { this.metricsEnabled = metricsEnabled; } + @Autowired public MetricsController(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } @@ -66,11 +64,11 @@ public class MetricsController { return ResponseEntity.ok(status); } - @GetMapping("/loads") + @GetMapping("/load") @Operation( summary = "GET request count", description = - "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.") + "This endpoint returns the total count of GET requests for a specific endpoint or all endpoints.") public ResponseEntity getPageLoads( @RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") Optional endpoint) { @@ -78,44 +76,33 @@ public class MetricsController { return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); } try { - - double count = 0.0; - - for (Meter meter : meterRegistry.getMeters()) { - if (meter.getId().getName().equals("http.requests")) { - String method = meter.getId().getTag("method"); - if (method != null && "GET".equals(method)) { - - if (endpoint.isPresent() && !endpoint.get().isBlank()) { - if (!endpoint.get().startsWith("/")) { - endpoint = Optional.of("/" + endpoint.get()); - } - System.out.println( - "loads " - + endpoint.get() - + " vs " - + meter.getId().getTag("uri")); - if (endpoint.get().equals(meter.getId().getTag("uri"))) { - if (meter instanceof Counter) { - count += ((Counter) meter).count(); - } - } - } else { - if (meter instanceof Counter) { - count += ((Counter) meter).count(); - } - } - } - } - } - + double count = getRequestCount("GET", endpoint); return ResponseEntity.ok(count); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } - @GetMapping("/loads/all") + @GetMapping("/load/unique") + @Operation( + summary = "Unique users count for GET requests", + description = + "This endpoint returns the count of unique users for GET requests for a specific endpoint or all endpoints.") + public ResponseEntity getUniquePageLoads( + @RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") + Optional endpoint) { + if (!metricsEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + double count = getUniqueUserCount("GET", endpoint); + return ResponseEntity.ok(count); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + @GetMapping("/load/all") @Operation( summary = "GET requests count for all endpoints", description = "This endpoint returns the count of GET requests for each endpoint.") @@ -124,37 +111,191 @@ public class MetricsController { return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); } try { - Map counts = new HashMap<>(); - - for (Meter meter : meterRegistry.getMeters()) { - if (meter.getId().getName().equals("http.requests")) { - String method = meter.getId().getTag("method"); - if (method != null && "GET".equals(method)) { - String uri = meter.getId().getTag("uri"); - if (uri != null) { - double currentCount = counts.getOrDefault(uri, 0.0); - if (meter instanceof Counter) { - currentCount += ((Counter) meter).count(); - } - counts.put(uri, currentCount); - } - } - } - } - - List results = - counts.entrySet().stream() - .map(entry -> new EndpointCount(entry.getKey(), entry.getValue())) - .sorted(Comparator.comparing(EndpointCount::getCount).reversed()) - .collect(Collectors.toList()); - + List results = getEndpointCounts("GET"); return ResponseEntity.ok(results); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } - public class EndpointCount { + @GetMapping("/load/all/unique") + @Operation( + summary = "Unique users count for GET requests for all endpoints", + description = + "This endpoint returns the count of unique users for GET requests for each endpoint.") + public ResponseEntity getAllUniqueEndpointLoads() { + if (!metricsEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + List results = getUniqueUserCounts("GET"); + return ResponseEntity.ok(results); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + @GetMapping("/requests") + @Operation( + summary = "POST request count", + description = + "This endpoint returns the total count of POST requests for a specific endpoint or all endpoints.") + public ResponseEntity getTotalRequests( + @RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") + Optional endpoint) { + if (!metricsEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + double count = getRequestCount("POST", endpoint); + return ResponseEntity.ok(count); + } catch (Exception e) { + return ResponseEntity.ok(-1); + } + } + + @GetMapping("/requests/unique") + @Operation( + summary = "Unique users count for POST requests", + description = + "This endpoint returns the count of unique users for POST requests for a specific endpoint or all endpoints.") + public ResponseEntity getUniqueTotalRequests( + @RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") + Optional endpoint) { + if (!metricsEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + double count = getUniqueUserCount("POST", endpoint); + return ResponseEntity.ok(count); + } catch (Exception e) { + return ResponseEntity.ok(-1); + } + } + + @GetMapping("/requests/all") + @Operation( + summary = "POST requests count for all endpoints", + description = "This endpoint returns the count of POST requests for each endpoint.") + public ResponseEntity getAllPostRequests() { + if (!metricsEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + List results = getEndpointCounts("POST"); + return ResponseEntity.ok(results); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + @GetMapping("/requests/all/unique") + @Operation( + summary = "Unique users count for POST requests for all endpoints", + description = + "This endpoint returns the count of unique users for POST requests for each endpoint.") + public ResponseEntity getAllUniquePostRequests() { + if (!metricsEnabled) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); + } + try { + List results = getUniqueUserCounts("POST"); + return ResponseEntity.ok(results); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + private double getRequestCount(String method, Optional endpoint) { + log.info( + "Getting request count for method: {}, endpoint: {}", + method, + endpoint.orElse("all")); + double count = + meterRegistry.find("http.requests").tag("method", method).counters().stream() + .filter( + counter -> + !endpoint.isPresent() + || endpoint.get() + .equals(counter.getId().getTag("uri"))) + .mapToDouble(Counter::count) + .sum(); + log.info("Request count: {}", count); + return count; + } + + private List getEndpointCounts(String method) { + log.info("Getting endpoint counts for method: {}", method); + Map counts = new HashMap<>(); + meterRegistry + .find("http.requests") + .tag("method", method) + .counters() + .forEach( + counter -> { + String uri = counter.getId().getTag("uri"); + counts.merge(uri, counter.count(), Double::sum); + }); + + List result = + counts.entrySet().stream() + .map(entry -> new EndpointCount(entry.getKey(), entry.getValue())) + .sorted(Comparator.comparing(EndpointCount::getCount).reversed()) + .collect(Collectors.toList()); + log.info("Found {} endpoints with counts", result.size()); + return result; + } + + private double getUniqueUserCount(String method, Optional endpoint) { + log.info( + "Getting unique user count for method: {}, endpoint: {}", + method, + endpoint.orElse("all")); + Set uniqueUsers = new HashSet<>(); + meterRegistry.find("http.requests").tag("method", method).counters().stream() + .filter( + counter -> + !endpoint.isPresent() + || endpoint.get().equals(counter.getId().getTag("uri"))) + .forEach( + counter -> { + String session = counter.getId().getTag("session"); + if (session != null) { + uniqueUsers.add(session); + } + }); + log.info("Unique user count: {}", uniqueUsers.size()); + return uniqueUsers.size(); + } + + private List getUniqueUserCounts(String method) { + log.info("Getting unique user counts for method: {}", method); + Map> uniqueUsers = new HashMap<>(); + + meterRegistry + .find("http.requests") + .tag("method", method) + .counters() + .forEach( + counter -> { + String uri = counter.getId().getTag("uri"); + String session = counter.getId().getTag("session"); + if (uri != null && session != null) { + uniqueUsers.computeIfAbsent(uri, k -> new HashSet<>()).add(session); + } + }); + + List result = + uniqueUsers.entrySet().stream() + .map(entry -> new EndpointCount(entry.getKey(), entry.getValue().size())) + .sorted(Comparator.comparing(EndpointCount::getCount).reversed()) + .collect(Collectors.toList()); + + log.info("Found {} endpoints with unique user counts", result.size()); + return result; + } + + public static class EndpointCount { private String endpoint; private double count; @@ -180,86 +321,6 @@ public class MetricsController { } } - @GetMapping("/requests") - @Operation( - summary = "POST request count", - description = - "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.") - public ResponseEntity getTotalRequests( - @RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint") - Optional endpoint) { - if (!metricsEnabled) { - return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); - } - try { - double count = 0.0; - - for (Meter meter : meterRegistry.getMeters()) { - if (meter.getId().getName().equals("http.requests")) { - String method = meter.getId().getTag("method"); - if (method != null && "POST".equals(method)) { - if (endpoint.isPresent() && !endpoint.get().isBlank()) { - if (!endpoint.get().startsWith("/")) { - endpoint = Optional.of("/" + endpoint.get()); - } - if (endpoint.get().equals(meter.getId().getTag("uri"))) { - if (meter instanceof Counter) { - count += ((Counter) meter).count(); - } - } - } else { - if (meter instanceof Counter) { - count += ((Counter) meter).count(); - } - } - } - } - } - return ResponseEntity.ok(count); - } catch (Exception e) { - return ResponseEntity.ok(-1); - } - } - - @GetMapping("/requests/all") - @Operation( - summary = "POST requests count for all endpoints", - description = "This endpoint returns the count of POST requests for each endpoint.") - public ResponseEntity getAllPostRequests() { - if (!metricsEnabled) { - return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled."); - } - try { - Map counts = new HashMap<>(); - - for (Meter meter : meterRegistry.getMeters()) { - if (meter.getId().getName().equals("http.requests")) { - String method = meter.getId().getTag("method"); - if (method != null && "POST".equals(method)) { - String uri = meter.getId().getTag("uri"); - if (uri != null) { - double currentCount = counts.getOrDefault(uri, 0.0); - if (meter instanceof Counter) { - currentCount += ((Counter) meter).count(); - } - counts.put(uri, currentCount); - } - } - } - } - - List results = - counts.entrySet().stream() - .map(entry -> new EndpointCount(entry.getKey(), entry.getValue())) - .sorted(Comparator.comparing(EndpointCount::getCount).reversed()) - .collect(Collectors.toList()); - - return ResponseEntity.ok(results); - } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); - } - } - @GetMapping("/uptime") public ResponseEntity getUptime() { if (!metricsEnabled) { diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java index 266d4520..46c92633 100644 --- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java +++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java @@ -12,6 +12,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import lombok.Data; +import lombok.ToString; import stirling.software.SPDF.config.YamlPropertySourceFactory; import stirling.software.SPDF.model.provider.GithubProvider; import stirling.software.SPDF.model.provider.GoogleProvider; @@ -21,225 +23,56 @@ import stirling.software.SPDF.model.provider.UnsupportedProviderException; @Configuration @ConfigurationProperties(prefix = "") @PropertySource(value = "file:./configs/settings.yml", factory = YamlPropertySourceFactory.class) +@Data public class ApplicationProperties { - private Security security; - private System system; - private Ui ui; - private Endpoints endpoints; - private Metrics metrics; - private AutomaticallyGenerated automaticallyGenerated; - private AutoPipeline autoPipeline; + + private Legal legal = new Legal(); + private Security security = new Security(); + private System system = new System(); + private Ui ui = new Ui(); + private Endpoints endpoints = new Endpoints(); + private Metrics metrics = new Metrics(); + private AutomaticallyGenerated automaticallyGenerated = new AutomaticallyGenerated(); + private EnterpriseEdition enterpriseEdition = new EnterpriseEdition(); + private AutoPipeline autoPipeline = new AutoPipeline(); private static final Logger logger = LoggerFactory.getLogger(ApplicationProperties.class); - public AutoPipeline getAutoPipeline() { - return autoPipeline != null ? autoPipeline : new AutoPipeline(); - } - - public void setAutoPipeline(AutoPipeline autoPipeline) { - this.autoPipeline = autoPipeline; - } - - public Security getSecurity() { - return security != null ? security : new Security(); - } - - public void setSecurity(Security security) { - this.security = security; - } - - public System getSystem() { - return system != null ? system : new System(); - } - - public void setSystem(System system) { - this.system = system; - } - - public Ui getUi() { - return ui != null ? ui : new Ui(); - } - - public void setUi(Ui ui) { - this.ui = ui; - } - - public Endpoints getEndpoints() { - return endpoints != null ? endpoints : new Endpoints(); - } - - public void setEndpoints(Endpoints endpoints) { - this.endpoints = endpoints; - } - - public Metrics getMetrics() { - return metrics != null ? metrics : new Metrics(); - } - - public void setMetrics(Metrics metrics) { - this.metrics = metrics; - } - - public AutomaticallyGenerated getAutomaticallyGenerated() { - return automaticallyGenerated != null - ? automaticallyGenerated - : new AutomaticallyGenerated(); - } - - public void setAutomaticallyGenerated(AutomaticallyGenerated automaticallyGenerated) { - this.automaticallyGenerated = automaticallyGenerated; - } - - @Override - public String toString() { - return "ApplicationProperties [security=" - + security - + ", system=" - + system - + ", ui=" - + ui - + ", endpoints=" - + endpoints - + ", metrics=" - + metrics - + ", automaticallyGenerated=" - + automaticallyGenerated - + ", autoPipeline=" - + autoPipeline - + "]"; - } - + @Data public static class AutoPipeline { private String outputFolder; - - public String getOutputFolder() { - return outputFolder; - } - - public void setOutputFolder(String outputFolder) { - this.outputFolder = outputFolder; - } - - @Override - public String toString() { - return "AutoPipeline [outputFolder=" + outputFolder + "]"; - } } + @Data + public static class Legal { + private String termsAndConditions; + private String privacyPolicy; + private String accessibilityStatement; + private String cookiePolicy; + private String impressum; + } + + @Data public static class Security { private Boolean enableLogin; private Boolean csrfDisabled; - private InitialLogin initialLogin; - private OAUTH2 oauth2; + private InitialLogin initialLogin = new InitialLogin(); + private OAUTH2 oauth2 = new OAUTH2(); private int loginAttemptCount; private long loginResetTimeMinutes; private String loginMethod = "all"; - public String getLoginMethod() { - return loginMethod; - } - - public void setLoginMethod(String loginMethod) { - this.loginMethod = loginMethod; - } - - public int getLoginAttemptCount() { - return loginAttemptCount; - } - - public void setLoginAttemptCount(int loginAttemptCount) { - this.loginAttemptCount = loginAttemptCount; - } - - public long getLoginResetTimeMinutes() { - return loginResetTimeMinutes; - } - - public void setLoginResetTimeMinutes(long loginResetTimeMinutes) { - this.loginResetTimeMinutes = loginResetTimeMinutes; - } - - public InitialLogin getInitialLogin() { - return initialLogin != null ? initialLogin : new InitialLogin(); - } - - public void setInitialLogin(InitialLogin initialLogin) { - this.initialLogin = initialLogin; - } - - public OAUTH2 getOAUTH2() { - return oauth2 != null ? oauth2 : new OAUTH2(); - } - - public void setOAUTH2(OAUTH2 oauth2) { - this.oauth2 = oauth2; - } - - public Boolean getEnableLogin() { - return enableLogin; - } - - public void setEnableLogin(Boolean enableLogin) { - this.enableLogin = enableLogin; - } - - public Boolean getCsrfDisabled() { - return csrfDisabled; - } - - public void setCsrfDisabled(Boolean csrfDisabled) { - this.csrfDisabled = csrfDisabled; - } - - @Override - public String toString() { - return "Security [enableLogin=" - + enableLogin - + ", oauth2=" - + oauth2 - + ", initialLogin=" - + initialLogin - + ", csrfDisabled=" - + csrfDisabled - + ", loginMethod=" - + loginMethod - + "]"; - } - + @Data public static class InitialLogin { private String username; - private String password; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public String toString() { - return "InitialLogin [username=" - + username - + ", password=" - + (password != null && !password.isEmpty() ? "MASKED" : "NULL") - + "]"; - } + @ToString.Exclude private String password; } + @Data public static class OAUTH2 { private Boolean enabled = false; private String issuer; private String clientId; - private String clientSecret; + @ToString.Exclude private String clientSecret; private Boolean autoCreateUser = false; private Boolean blockRegistration = false; private String useAsUsername; @@ -247,74 +80,6 @@ public class ApplicationProperties { private String provider; private Client client = new Client(); - public Boolean getEnabled() { - return enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; - } - - public String getIssuer() { - return issuer; - } - - public void setIssuer(String issuer) { - this.issuer = issuer; - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public Boolean getAutoCreateUser() { - return autoCreateUser; - } - - public void setAutoCreateUser(Boolean autoCreateUser) { - this.autoCreateUser = autoCreateUser; - } - - public Boolean getBlockRegistration() { - return blockRegistration; - } - - public void setBlockRegistration(Boolean blockRegistration) { - this.blockRegistration = blockRegistration; - } - - public String getUseAsUsername() { - return useAsUsername; - } - - public void setUseAsUsername(String useAsUsername) { - this.useAsUsername = useAsUsername; - } - - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public Collection getScopes() { - return scopes; - } - public void setScopes(String scopes) { List scopesList = Arrays.stream(scopes.split(",")) @@ -323,26 +88,12 @@ public class ApplicationProperties { this.scopes.addAll(scopesList); } - public Client getClient() { - return client; - } - - public void setClient(Client client) { - this.client = client; - } - protected boolean isValid(String value, String name) { - if (value != null && !value.trim().isEmpty()) { - return true; - } - return false; + return value != null && !value.trim().isEmpty(); } protected boolean isValid(Collection value, String name) { - if (value != null && !value.isEmpty()) { - return true; - } - return false; + return value != null && !value.isEmpty(); } public boolean isSettingsValid() { @@ -353,31 +104,7 @@ public class ApplicationProperties { && isValid(this.getUseAsUsername(), "useAsUsername"); } - @Override - public String toString() { - return "OAUTH2 [enabled=" - + enabled - + ", issuer=" - + issuer - + ", clientId=" - + clientId - + ", clientSecret=" - + (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL") - + ", autoCreateUser=" - + autoCreateUser - + ", blockRegistration=" - + blockRegistration - + ", useAsUsername=" - + useAsUsername - + ", provider=" - + provider - + ", client=" - + client - + ", scopes=" - + scopes - + "]"; - } - + @Data public static class Client { private GoogleProvider google = new GoogleProvider(); private GithubProvider github = new GithubProvider(); @@ -392,50 +119,15 @@ public class ApplicationProperties { case "keycloak": return getKeycloak(); default: - break; + throw new UnsupportedProviderException( + "Logout from the provider is not supported? Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues"); } - throw new UnsupportedProviderException( - "Logout from the provider is not supported? Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues"); - } - - public GoogleProvider getGoogle() { - return google; - } - - public void setGoogle(GoogleProvider google) { - this.google = google; - } - - public GithubProvider getGithub() { - return github; - } - - public void setGithub(GithubProvider github) { - this.github = github; - } - - public KeycloakProvider getKeycloak() { - return keycloak; - } - - public void setKeycloak(KeycloakProvider keycloak) { - this.keycloak = keycloak; - } - - @Override - public String toString() { - return "Client [google=" - + google - + ", github=" - + github - + ", keycloak=" - + keycloak - + "]"; } } } } + @Data public static class System { private String defaultLocale; private Boolean googlevisibility; @@ -443,184 +135,67 @@ public class ApplicationProperties { private Boolean showUpdateOnlyAdmin; private boolean customHTMLFiles; private String tessdataDir; - - public String getTessdataDir() { - return tessdataDir; - } - - public void setTessdataDir(String tessdataDir) { - this.tessdataDir = tessdataDir; - } - - public boolean isCustomHTMLFiles() { - return customHTMLFiles; - } - - public void setCustomHTMLFiles(boolean customHTMLFiles) { - this.customHTMLFiles = customHTMLFiles; - } - - public boolean getShowUpdateOnlyAdmin() { - return showUpdateOnlyAdmin; - } - - public void setShowUpdateOnlyAdmin(boolean showUpdateOnlyAdmin) { - this.showUpdateOnlyAdmin = showUpdateOnlyAdmin; - } - - public boolean getShowUpdate() { - return showUpdate; - } - - public void setShowUpdate(boolean showUpdate) { - this.showUpdate = showUpdate; - } - private Boolean enableAlphaFunctionality; - - public Boolean getEnableAlphaFunctionality() { - return enableAlphaFunctionality; - } - - public void setEnableAlphaFunctionality(Boolean enableAlphaFunctionality) { - this.enableAlphaFunctionality = enableAlphaFunctionality; - } - - public String getDefaultLocale() { - return defaultLocale; - } - - public void setDefaultLocale(String defaultLocale) { - this.defaultLocale = defaultLocale; - } - - public Boolean getGooglevisibility() { - return googlevisibility; - } - - public void setGooglevisibility(Boolean googlevisibility) { - this.googlevisibility = googlevisibility; - } - - @Override - public String toString() { - return "System [defaultLocale=" - + defaultLocale - + ", googlevisibility=" - + googlevisibility - + ", enableAlphaFunctionality=" - + enableAlphaFunctionality - + ", showUpdate=" - + showUpdate - + ", showUpdateOnlyAdmin=" - + showUpdateOnlyAdmin - + "]"; - } } + @Data public static class Ui { private String appName; private String homeDescription; private String appNameNavbar; public String getAppName() { - if (appName != null && appName.trim().length() == 0) return null; - return appName; - } - - public void setAppName(String appName) { - this.appName = appName; + return appName != null && appName.trim().length() > 0 ? appName : null; } public String getHomeDescription() { - if (homeDescription != null && homeDescription.trim().length() == 0) return null; - return homeDescription; - } - - public void setHomeDescription(String homeDescription) { - this.homeDescription = homeDescription; + return homeDescription != null && homeDescription.trim().length() > 0 + ? homeDescription + : null; } public String getAppNameNavbar() { - if (appNameNavbar != null && appNameNavbar.trim().length() == 0) return null; - return appNameNavbar; - } - - public void setAppNameNavbar(String appNameNavbar) { - this.appNameNavbar = appNameNavbar; - } - - @Override - public String toString() { - return "UserInterface [appName=" - + appName - + ", homeDescription=" - + homeDescription - + ", appNameNavbar=" - + appNameNavbar - + "]"; + return appNameNavbar != null && appNameNavbar.trim().length() > 0 + ? appNameNavbar + : null; } } + @Data public static class Endpoints { private List toRemove; private List groupsToRemove; - - public List getToRemove() { - return toRemove; - } - - public void setToRemove(List toRemove) { - this.toRemove = toRemove; - } - - public List getGroupsToRemove() { - return groupsToRemove; - } - - public void setGroupsToRemove(List groupsToRemove) { - this.groupsToRemove = groupsToRemove; - } - - @Override - public String toString() { - return "Endpoints [toRemove=" + toRemove + ", groupsToRemove=" + groupsToRemove + "]"; - } } + @Data public static class Metrics { private Boolean enabled; - - public Boolean getEnabled() { - return enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; - } - - @Override - public String toString() { - return "Metrics [enabled=" + enabled + "]"; - } } + @Data public static class AutomaticallyGenerated { - private String key; + @ToString.Exclude private String key; + } - public String getKey() { - return key; - } + @Data + public static class EnterpriseEdition { + @ToString.Exclude private String key; + private CustomMetadata customMetadata = new CustomMetadata(); - public void setKey(String key) { - this.key = key; - } + @Data + public static class CustomMetadata { + private boolean autoUpdateMetadata; + private String author; + private String creator; + private String producer; - @Override - public String toString() { - return "AutomaticallyGenerated [key=" - + (key != null && !key.isEmpty() ? "MASKED" : "NULL") - + "]"; + public String getCreator() { + return creator == null || creator.trim().isEmpty() ? "Stirling-PDF" : creator; + } + + public String getProducer() { + return producer == null || producer.trim().isEmpty() ? "Stirling-PDF" : producer; + } } } } diff --git a/src/main/java/stirling/software/SPDF/repository/UserRepository.java b/src/main/java/stirling/software/SPDF/repository/UserRepository.java index 4f231e0f..0f5387f7 100644 --- a/src/main/java/stirling/software/SPDF/repository/UserRepository.java +++ b/src/main/java/stirling/software/SPDF/repository/UserRepository.java @@ -16,7 +16,6 @@ public interface UserRepository extends JpaRepository { @Query("FROM User u LEFT JOIN FETCH u.settings where upper(u.username) = upper(:username)") Optional findByUsernameIgnoreCaseWithSettings(@Param("username") String username); - Optional findByUsername(String username); Optional findByApiKey(String apiKey); diff --git a/src/main/java/stirling/software/SPDF/utils/PdfUtils.java b/src/main/java/stirling/software/SPDF/utils/PdfUtils.java index c1589902..160e01da 100644 --- a/src/main/java/stirling/software/SPDF/utils/PdfUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/PdfUtils.java @@ -6,7 +6,6 @@ import java.awt.image.RenderedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.zip.ZipEntry; @@ -37,8 +36,6 @@ import org.springframework.web.multipart.MultipartFile; import io.github.pixee.security.Filenames; -import stirling.software.SPDF.model.PdfMetadata; - public class PdfUtils { private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class); @@ -506,30 +503,6 @@ public class PdfUtils { return baos.toByteArray(); } - public static PdfMetadata extractMetadataFromPdf(PDDocument pdf) { - return PdfMetadata.builder() - .author(pdf.getDocumentInformation().getAuthor()) - .producer(pdf.getDocumentInformation().getProducer()) - .title(pdf.getDocumentInformation().getTitle()) - .creator(pdf.getDocumentInformation().getCreator()) - .subject(pdf.getDocumentInformation().getSubject()) - .keywords(pdf.getDocumentInformation().getKeywords()) - .creationDate(pdf.getDocumentInformation().getCreationDate()) - .modificationDate(pdf.getDocumentInformation().getModificationDate()) - .build(); - } - - public static void setMetadataToPdf(PDDocument pdf, PdfMetadata pdfMetadata) { - pdf.getDocumentInformation().setAuthor(pdfMetadata.getAuthor()); - pdf.getDocumentInformation().setProducer(pdfMetadata.getProducer()); - pdf.getDocumentInformation().setTitle(pdfMetadata.getTitle()); - pdf.getDocumentInformation().setCreator(pdfMetadata.getCreator()); - pdf.getDocumentInformation().setSubject(pdfMetadata.getSubject()); - pdf.getDocumentInformation().setKeywords(pdfMetadata.getKeywords()); - pdf.getDocumentInformation().setCreationDate(pdfMetadata.getCreationDate()); - pdf.getDocumentInformation().setModificationDate(Calendar.getInstance()); - } - /** Key for storing the dimensions of a rendered image in a map. */ private record PdfRenderSettingsKey(float mediaBoxWidth, float mediaBoxHeight, int rotation) {} diff --git a/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java b/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java index a9c404e1..7aeab8e1 100644 --- a/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java @@ -12,6 +12,7 @@ public class RequestUriUtils { return requestURI.startsWith(contextPath + "/css/") || requestURI.startsWith(contextPath + "/fonts/") || requestURI.startsWith(contextPath + "/js/") + || requestURI.endsWith(contextPath + "robots.txt") || requestURI.startsWith(contextPath + "/images/") || requestURI.startsWith(contextPath + "/public/") || requestURI.startsWith(contextPath + "/pdfjs/") @@ -22,4 +23,26 @@ public class RequestUriUtils { || requestURI.endsWith(".webmanifest") || requestURI.startsWith(contextPath + "/api/v1/info/status"); } + + public static boolean isTrackableResource(String requestURI) { + return isTrackableResource("", requestURI); + } + + public static boolean isTrackableResource(String contextPath, String requestURI) { + return !(requestURI.startsWith("/js") + || requestURI.startsWith("/v1/api-docs") + || requestURI.endsWith("robots.txt") + || requestURI.startsWith("/images") + || requestURI.endsWith(".png") + || requestURI.endsWith(".ico") + || requestURI.endsWith(".css") + || requestURI.endsWith(".map") + || requestURI.endsWith(".svg") + || requestURI.endsWith(".js") + || requestURI.contains("swagger") + || requestURI.startsWith("/api/v1/info") + || requestURI.startsWith("/site.webmanifest") + || requestURI.startsWith("/fonts") + || requestURI.startsWith("/pdfjs")); + } } diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index 4b19d941..edf93176 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -77,7 +77,11 @@ color=لون sponsor=راعٍ info=معلومات - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_bg_BG.properties b/src/main/resources/messages_bg_BG.properties index 442f8789..859fb0a2 100644 --- a/src/main/resources/messages_bg_BG.properties +++ b/src/main/resources/messages_bg_BG.properties @@ -77,7 +77,11 @@ color=Цвят sponsor=Спонсор info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index 4673d2d4..afa0eb1d 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_cs_CZ.properties b/src/main/resources/messages_cs_CZ.properties index a5396d39..ef0cdb26 100644 --- a/src/main/resources/messages_cs_CZ.properties +++ b/src/main/resources/messages_cs_CZ.properties @@ -77,7 +77,11 @@ color=Barva sponsor=Sponzor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_da_DK.properties b/src/main/resources/messages_da_DK.properties index 198c9d82..1260d104 100644 --- a/src/main/resources/messages_da_DK.properties +++ b/src/main/resources/messages_da_DK.properties @@ -77,7 +77,11 @@ color=Farve sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index a9034445..ceaf679c 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -77,7 +77,11 @@ color=Farbe sponsor=Sponsor info=Informationen - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_el_GR.properties b/src/main/resources/messages_el_GR.properties index ba1c4e57..6e4c1df4 100644 --- a/src/main/resources/messages_el_GR.properties +++ b/src/main/resources/messages_el_GR.properties @@ -77,7 +77,11 @@ color=Χρώμα sponsor=Yποστηρικτής info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index 46a28f6e..206fae04 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 58ae0f84..3fcfa3d5 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index cd28db08..31dcacd5 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -77,7 +77,11 @@ color=Color sponsor=Patrocinador info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 5a297eac..1ebbf542 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index f51e31d2..b563103e 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -77,7 +77,11 @@ color=Couleur sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_ga_IE.properties b/src/main/resources/messages_ga_IE.properties index 65b90cfa..8223da8a 100644 --- a/src/main/resources/messages_ga_IE.properties +++ b/src/main/resources/messages_ga_IE.properties @@ -77,7 +77,11 @@ color=Dath sponsor=Urraitheoir info=Eolas - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_hi_IN.properties b/src/main/resources/messages_hi_IN.properties index 24e68fbd..4c7137a1 100644 --- a/src/main/resources/messages_hi_IN.properties +++ b/src/main/resources/messages_hi_IN.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_hr_HR.properties b/src/main/resources/messages_hr_HR.properties index d669f1f7..980bda1a 100644 --- a/src/main/resources/messages_hr_HR.properties +++ b/src/main/resources/messages_hr_HR.properties @@ -77,7 +77,11 @@ color=Boja sponsor=Sponzor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_hu_HU.properties b/src/main/resources/messages_hu_HU.properties index 417c3909..11f1d8ba 100644 --- a/src/main/resources/messages_hu_HU.properties +++ b/src/main/resources/messages_hu_HU.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_id_ID.properties b/src/main/resources/messages_id_ID.properties index 109b57c0..dba627cd 100644 --- a/src/main/resources/messages_id_ID.properties +++ b/src/main/resources/messages_id_ID.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index b680c4cb..58505fcd 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -77,7 +77,11 @@ color=Colore sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index b7e64251..c0a441b8 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -77,7 +77,11 @@ color=色 sponsor=スポンサー info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index 3110922a..3c47f3c5 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -77,7 +77,11 @@ color=색상 sponsor=스폰서 info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties index b0ed1ca8..643e9ebe 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -77,7 +77,11 @@ color=Kleur sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_no_NB.properties b/src/main/resources/messages_no_NB.properties index a9794fbb..73309cb2 100644 --- a/src/main/resources/messages_no_NB.properties +++ b/src/main/resources/messages_no_NB.properties @@ -77,7 +77,11 @@ color=Farge sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index 7c4556ab..0800397a 100755 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -77,7 +77,11 @@ color=kolor sponsor=sponsor info=informacje - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index 4f3804c0..f6e93ba2 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -77,7 +77,11 @@ color=Cor sponsor=Patrocine info=Informações - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_pt_PT.properties b/src/main/resources/messages_pt_PT.properties index 9d13fd99..bce2fb45 100644 --- a/src/main/resources/messages_pt_PT.properties +++ b/src/main/resources/messages_pt_PT.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index e4d96c25..7c800454 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -77,7 +77,11 @@ color=Culoare sponsor=Sponsor info=Informații - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index 4fd23c09..4c02d934 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -77,7 +77,11 @@ color=Цвет sponsor=Спонсор info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_sk_SK.properties b/src/main/resources/messages_sk_SK.properties index 3452d732..968f29a8 100644 --- a/src/main/resources/messages_sk_SK.properties +++ b/src/main/resources/messages_sk_SK.properties @@ -77,7 +77,11 @@ color=Farba sponsor=Sponzorovať info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_sr_LATN_RS.properties b/src/main/resources/messages_sr_LATN_RS.properties index 53226f25..6744321f 100644 --- a/src/main/resources/messages_sr_LATN_RS.properties +++ b/src/main/resources/messages_sr_LATN_RS.properties @@ -77,7 +77,11 @@ color=Color sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index 3d159d3a..9a6232b4 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -77,7 +77,11 @@ color=Färg sponsor=Sponsor info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_th_TH.properties b/src/main/resources/messages_th_TH.properties index ae82a70f..c8e6232e 100644 --- a/src/main/resources/messages_th_TH.properties +++ b/src/main/resources/messages_th_TH.properties @@ -77,7 +77,11 @@ color=สี sponsor=ผู้สนับสนุน info=ข้อมูล - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_tr_TR.properties b/src/main/resources/messages_tr_TR.properties index c5d72ccf..0dd75373 100644 --- a/src/main/resources/messages_tr_TR.properties +++ b/src/main/resources/messages_tr_TR.properties @@ -77,7 +77,11 @@ color=Renk sponsor=Bağış info=Bilgi - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_uk_UA.properties b/src/main/resources/messages_uk_UA.properties index 41ca0038..e91a09fd 100644 --- a/src/main/resources/messages_uk_UA.properties +++ b/src/main/resources/messages_uk_UA.properties @@ -77,7 +77,11 @@ color=Колір sponsor=Спонсор info=Інформація - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_vi_VN.properties b/src/main/resources/messages_vi_VN.properties index 28ef3fa1..6d417a96 100644 --- a/src/main/resources/messages_vi_VN.properties +++ b/src/main/resources/messages_vi_VN.properties @@ -77,7 +77,11 @@ color=Màu sắc sponsor=Nhà tài trợ info=Thông tin - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index e0f312cf..a1c2059a 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -77,7 +77,11 @@ color=颜色 sponsor=赞助 info=信息 - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/messages_zh_TW.properties b/src/main/resources/messages_zh_TW.properties index 096a5625..6b523d13 100644 --- a/src/main/resources/messages_zh_TW.properties +++ b/src/main/resources/messages_zh_TW.properties @@ -77,7 +77,11 @@ color=顏色 sponsor=贊助 info=Info - +legal.privacy=Privacy Policy +legal.terms=Terms and Conditions +legal.accessibility=Accessibility +legal.cookie=Cookie Policy +legal.impressum=Impressum ############### # Pipeline # diff --git a/src/main/resources/settings.yml.template b/src/main/resources/settings.yml.template index 2e06ea9f..2a5400b6 100644 --- a/src/main/resources/settings.yml.template +++ b/src/main/resources/settings.yml.template @@ -48,6 +48,22 @@ security: scopes: openid, profile, email # Specify the scopes for which the application will request permissions provider: google # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak' +# Enterprise edition settings unused for now please ignore! +EnterpriseEdition: + key: 00000000-0000-0000-0000-000000000000 + CustomMetadata: + autoUpdateMetadata: true # set to 'true' to automatically update metadata with below values + author: username # Supports text such as 'John Doe' or types such as username + creator: Stirling-PDF # Supports text such as 'Company-PDF' + producer: Stirling-PDF # Supports text such as 'Company-PDF' + +legal: + termsAndConditions: '' # URL to the terms and conditions of your application (e.g. https://example.com/terms) Empty string to disable or filename to load from local file in static folder + privacyPolicy: '' # URL to the privacy policy of your application (e.g. https://example.com/privacy) Empty string to disable or filename to load from local file in static folder + accessibilityStatement: '' # URL to the accessibility statement of your application (e.g. https://example.com/accessibility) Empty string to disable or filename to load from local file in static folder + cookiePolicy: '' # URL to the cookie policy of your application (e.g. https://example.com/cookie) Empty string to disable or filename to load from local file in static folder + impressum: '' # URL to the impressum of your application (e.g. https://example.com/impressum) Empty string to disable or filename to load from local file in static folder + system: defaultLocale: en-US # Set the default language (e.g. 'de-DE', 'fr-FR', etc) googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index 0654cac9..55635c69 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -446,7 +446,7 @@ function detectImageType(uint8Array) { // Check for TIFF signature (little-endian and big-endian) if ((uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) || - (uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)) { + (uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)) { return 'TIFF'; } diff --git a/src/main/resources/templates/fragments/common.html b/src/main/resources/templates/fragments/common.html index 59a3b5f4..96d52157 100644 --- a/src/main/resources/templates/fragments/common.html +++ b/src/main/resources/templates/fragments/common.html @@ -24,7 +24,7 @@ - + @@ -35,10 +35,10 @@ - + - + @@ -58,17 +58,21 @@ - + + + + + - + - + diff --git a/src/main/resources/templates/fragments/footer.html b/src/main/resources/templates/fragments/footer.html index 7d0c1a54..40f64419 100644 --- a/src/main/resources/templates/fragments/footer.html +++ b/src/main/resources/templates/fragments/footer.html @@ -5,6 +5,11 @@ diff --git a/src/main/resources/templates/misc/add-page-numbers.html b/src/main/resources/templates/misc/add-page-numbers.html index eb9a87de..186253b6 100644 --- a/src/main/resources/templates/misc/add-page-numbers.html +++ b/src/main/resources/templates/misc/add-page-numbers.html @@ -94,10 +94,9 @@
diff --git a/src/main/resources/templates/multi-tool.html b/src/main/resources/templates/multi-tool.html index 9f165014..61fcc28e 100644 --- a/src/main/resources/templates/multi-tool.html +++ b/src/main/resources/templates/multi-tool.html @@ -110,4 +110,4 @@ - \ No newline at end of file + diff --git a/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java b/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java index 03a52663..a650e891 100644 --- a/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java +++ b/src/test/java/stirling/software/SPDF/utils/PdfUtilsTest.java @@ -49,12 +49,5 @@ public class PdfUtilsTest { assertTrue(PdfUtils.hasImagesOnPage(page)); } - @Test - void testExtractMetadataFromPdf() throws IOException { - PDDocument document = Mockito.mock(PDDocument.class); - Mockito.when(document.getDocumentInformation()).thenReturn(Mockito.mock(org.apache.pdfbox.pdmodel.PDDocumentInformation.class)); - PdfMetadata metadata = PdfUtils.extractMetadataFromPdf(document); - assertNotNull(metadata); - } }