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 <a> * final touches Signed-off-by: a <a> * final touches Signed-off-by: a <a> * final touches Signed-off-by: a <a> * final touches Signed-off-by: a <a> * final touches Signed-off-by: a <a> * final touches Signed-off-by: a <a> * Update translation files (#1888) Signed-off-by: GitHub Action <action@github.com> Co-authored-by: GitHub Action <action@github.com> --------- Signed-off-by: a <a> Signed-off-by: GitHub Action <action@github.com> Co-authored-by: a <a> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
4d47e535b5
commit
8c01425eee
74 changed files with 749 additions and 772 deletions
|
@ -1,4 +1,3 @@
|
||||||
version: '3.3'
|
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security-Fat
|
container_name: Stirling-PDF-Security-Fat
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
version: '3.3'
|
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
version: '3.3'
|
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
version: '3.3'
|
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Ultra-Lite-Security
|
container_name: Stirling-PDF-Ultra-Lite-Security
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
version: '3.3'
|
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Ultra-Lite
|
container_name: Stirling-PDF-Ultra-Lite
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
version: '3.3'
|
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF
|
container_name: Stirling-PDF
|
||||||
|
|
25
src/main/java/stirling/software/SPDF/EE/EEAppConfig.java
Normal file
25
src/main/java/stirling/software/SPDF/EE/EEAppConfig.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,6 @@ public class SPdfApplication {
|
||||||
|
|
||||||
@Autowired private Environment env;
|
@Autowired private Environment env;
|
||||||
|
|
||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
private static String serverPortStatic;
|
private static String serverPortStatic;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class AppUpdateService {
|
||||||
@Bean(name = "shouldShow")
|
@Bean(name = "shouldShow")
|
||||||
@Scope("request")
|
@Scope("request")
|
||||||
public boolean shouldShow() {
|
public boolean shouldShow() {
|
||||||
boolean showUpdate = applicationProperties.getSystem().getShowUpdate();
|
boolean showUpdate = applicationProperties.getSystem().isShowUpdate();
|
||||||
boolean showAdminResult = (showAdmin != null) ? showAdmin.getShowUpdateOnlyAdmins() : true;
|
boolean showAdminResult = (showAdmin != null) ? showAdmin.getShowUpdateOnlyAdmins() : true;
|
||||||
return showUpdate && showAdminResult;
|
return showUpdate && showAdminResult;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class MetricsFilter extends OncePerRequestFilter {
|
public class MetricsFilter extends OncePerRequestFilter {
|
||||||
|
@ -30,32 +31,16 @@ public class MetricsFilter extends OncePerRequestFilter {
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
String uri = request.getRequestURI();
|
String uri = request.getRequestURI();
|
||||||
|
|
||||||
// System.out.println("uri="+uri + ", method=" + request.getMethod() );
|
if (RequestUriUtils.isTrackableResource(request.getContextPath(), uri)) {
|
||||||
// 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"))) {
|
|
||||||
|
|
||||||
Counter counter =
|
Counter counter =
|
||||||
Counter.builder("http.requests")
|
Counter.builder("http.requests")
|
||||||
.tag("uri", uri)
|
.tag("session", request.getSession().getId())
|
||||||
.tag("method", request.getMethod())
|
.tag("method", request.getMethod())
|
||||||
|
.tag("uri", uri)
|
||||||
.register(meterRegistry);
|
.register(meterRegistry);
|
||||||
|
|
||||||
counter.increment();
|
counter.increment();
|
||||||
// System.out.println("Counted");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ class AppUpdateAuthService implements ShowAdminInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getShowUpdateOnlyAdmins() {
|
public boolean getShowUpdateOnlyAdmins() {
|
||||||
boolean showUpdate = applicationProperties.getSystem().getShowUpdate();
|
boolean showUpdate = applicationProperties.getSystem().isShowUpdate();
|
||||||
if (!showUpdate) {
|
if (!showUpdate) {
|
||||||
return showUpdate;
|
return showUpdate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,8 +152,8 @@ public class SecurityConfiguration {
|
||||||
.authenticated());
|
.authenticated());
|
||||||
|
|
||||||
// Handle OAUTH2 Logins
|
// Handle OAUTH2 Logins
|
||||||
if (applicationProperties.getSecurity().getOAUTH2() != null
|
if (applicationProperties.getSecurity().getOauth2() != null
|
||||||
&& applicationProperties.getSecurity().getOAUTH2().getEnabled()
|
&& applicationProperties.getSecurity().getOauth2().getEnabled()
|
||||||
&& !applicationProperties
|
&& !applicationProperties
|
||||||
.getSecurity()
|
.getSecurity()
|
||||||
.getLoginMethod()
|
.getLoginMethod()
|
||||||
|
@ -222,7 +222,7 @@ public class SecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ClientRegistration> googleClientRegistration() {
|
private Optional<ClientRegistration> googleClientRegistration() {
|
||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||||
if (oauth == null || !oauth.getEnabled()) {
|
if (oauth == null || !oauth.getEnabled()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ public class SecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ClientRegistration> keycloakClientRegistration() {
|
private Optional<ClientRegistration> keycloakClientRegistration() {
|
||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||||
if (oauth == null || !oauth.getEnabled()) {
|
if (oauth == null || !oauth.getEnabled()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ public class SecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ClientRegistration> githubClientRegistration() {
|
private Optional<ClientRegistration> githubClientRegistration() {
|
||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||||
if (oauth == null || !oauth.getEnabled()) {
|
if (oauth == null || !oauth.getEnabled()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
@ -304,7 +304,7 @@ public class SecurityConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ClientRegistration> oidcClientRegistration() {
|
private Optional<ClientRegistration> oidcClientRegistration() {
|
||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||||
if (oauth == null
|
if (oauth == null
|
||||||
|| oauth.getIssuer() == null
|
|| oauth.getIssuer() == null
|
||||||
|| oauth.getIssuer().isEmpty()
|
|| oauth.getIssuer().isEmpty()
|
||||||
|
@ -352,7 +352,7 @@ public class SecurityConfiguration {
|
||||||
String useAsUsername =
|
String useAsUsername =
|
||||||
applicationProperties
|
applicationProperties
|
||||||
.getSecurity()
|
.getSecurity()
|
||||||
.getOAUTH2()
|
.getOauth2()
|
||||||
.getUseAsUsername();
|
.getUseAsUsername();
|
||||||
Optional<User> userOpt =
|
Optional<User> userOpt =
|
||||||
userService.findByUsernameIgnoreCase(
|
userService.findByUsernameIgnoreCase(
|
||||||
|
|
|
@ -159,7 +159,10 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (String pattern : permitAllPatterns) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
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.session.SessionInformation;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class CustomOAuth2AuthenticationSuccessHandler
|
||||||
// Redirect to the original destination
|
// Redirect to the original destination
|
||||||
super.onAuthenticationSuccess(request, response, authentication);
|
super.onAuthenticationSuccess(request, response, authentication);
|
||||||
} else {
|
} else {
|
||||||
OAUTH2 oAuth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oAuth = applicationProperties.getSecurity().getOauth2();
|
||||||
|
|
||||||
if (loginAttemptService.isBlocked(username)) {
|
if (loginAttemptService.isBlocked(username)) {
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||||
|
|
||||||
if (authentication instanceof OAuth2AuthenticationToken) {
|
if (authentication instanceof OAuth2AuthenticationToken) {
|
||||||
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
|
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
||||||
OAUTH2 oauth2 = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();
|
||||||
String usernameAttribute = oauth2.getUseAsUsername();
|
String usernameAttribute = oauth2.getUseAsUsername();
|
||||||
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) {
|
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) {
|
||||||
Client client = oauth2.getClient();
|
Client client = oauth2.getClient();
|
||||||
|
|
|
@ -27,9 +27,9 @@ import io.github.pixee.security.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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.PdfMetadata;
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -51,7 +51,7 @@ public class SplitPDFController {
|
||||||
// open the pdf document
|
// open the pdf document
|
||||||
|
|
||||||
PDDocument document = Loader.loadPDF(file.getBytes());
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
PdfMetadata metadata = PdfUtils.extractMetadataFromPdf(document);
|
PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
|
||||||
int totalPages = document.getNumberOfPages();
|
int totalPages = document.getNumberOfPages();
|
||||||
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
|
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
|
||||||
System.out.println(
|
System.out.println(
|
||||||
|
@ -79,7 +79,7 @@ public class SplitPDFController {
|
||||||
previousPageNumber = splitPoint + 1;
|
previousPageNumber = splitPoint + 1;
|
||||||
|
|
||||||
// Transfer metadata to split pdf
|
// Transfer metadata to split pdf
|
||||||
PdfUtils.setMetadataToPdf(splitDocument, metadata);
|
PdfMetadataService.setMetadataToPdf(splitDocument, metadata);
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
splitDocument.save(baos);
|
splitDocument.save(baos);
|
||||||
|
|
|
@ -31,9 +31,9 @@ import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import stirling.software.SPDF.config.PdfMetadataService;
|
||||||
import stirling.software.SPDF.model.PdfMetadata;
|
import stirling.software.SPDF.model.PdfMetadata;
|
||||||
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
|
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -258,7 +258,7 @@ public class SplitPdfByChaptersController {
|
||||||
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
List<ByteArrayOutputStream> splitDocumentsBoas = new ArrayList<>();
|
||||||
PdfMetadata metadata = null;
|
PdfMetadata metadata = null;
|
||||||
if (includeMetadata) {
|
if (includeMetadata) {
|
||||||
metadata = PdfUtils.extractMetadataFromPdf(sourceDocument);
|
metadata = PdfMetadataService.extractMetadataFromPdf(sourceDocument);
|
||||||
}
|
}
|
||||||
for (Bookmark bookmark : bookmarks) {
|
for (Bookmark bookmark : bookmarks) {
|
||||||
try (PDDocument splitDocument = new PDDocument()) {
|
try (PDDocument splitDocument = new PDDocument()) {
|
||||||
|
@ -273,7 +273,7 @@ public class SplitPdfByChaptersController {
|
||||||
}
|
}
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
if (includeMetadata) {
|
if (includeMetadata) {
|
||||||
PdfUtils.setMetadataToPdf(splitDocument, metadata);
|
PdfMetadataService.setMetadataToPdf(splitDocument, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
splitDocument.save(baos);
|
splitDocument.save(baos);
|
||||||
|
|
|
@ -208,8 +208,8 @@ public class UserController {
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@PostMapping("/admin/saveUser")
|
@PostMapping("/admin/saveUser")
|
||||||
public RedirectView saveUser(
|
public RedirectView saveUser(
|
||||||
@RequestParam String username,
|
@RequestParam(name = "username", required = true) String username,
|
||||||
@RequestParam(name = "password", required = false) String password,
|
@RequestParam(name = "password", required = true) String password,
|
||||||
@RequestParam(name = "role") String role,
|
@RequestParam(name = "role") String role,
|
||||||
@RequestParam(name = "authType") String authType,
|
@RequestParam(name = "authType") String authType,
|
||||||
@RequestParam(name = "forceChange", required = false, defaultValue = "false")
|
@RequestParam(name = "forceChange", required = false, defaultValue = "false")
|
||||||
|
|
|
@ -25,9 +25,9 @@ import io.github.pixee.security.Filenames;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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.PdfMetadata;
|
||||||
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
import stirling.software.SPDF.model.api.misc.FlattenRequest;
|
||||||
import stirling.software.SPDF.utils.PdfUtils;
|
|
||||||
import stirling.software.SPDF.utils.WebResponseUtils;
|
import stirling.software.SPDF.utils.WebResponseUtils;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -46,7 +46,7 @@ public class FlattenController {
|
||||||
MultipartFile file = request.getFileInput();
|
MultipartFile file = request.getFileInput();
|
||||||
|
|
||||||
PDDocument document = Loader.loadPDF(file.getBytes());
|
PDDocument document = Loader.loadPDF(file.getBytes());
|
||||||
PdfMetadata metadata = PdfUtils.extractMetadataFromPdf(document);
|
PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document);
|
||||||
Boolean flattenOnlyForms = request.getFlattenOnlyForms();
|
Boolean flattenOnlyForms = request.getFlattenOnlyForms();
|
||||||
|
|
||||||
if (Boolean.TRUE.equals(flattenOnlyForms)) {
|
if (Boolean.TRUE.equals(flattenOnlyForms)) {
|
||||||
|
@ -80,7 +80,7 @@ public class FlattenController {
|
||||||
logger.error("exception", e);
|
logger.error("exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PdfUtils.setMetadataToPdf(newDocument, metadata);
|
PdfMetadataService.setMetadataToPdf(newDocument, metadata);
|
||||||
return WebResponseUtils.pdfDocToWebResponse(
|
return WebResponseUtils.pdfDocToWebResponse(
|
||||||
newDocument, Filenames.toSimpleFileName(file.getOriginalFilename()));
|
newDocument, Filenames.toSimpleFileName(file.getOriginalFilename()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
|
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
@ -75,7 +76,8 @@ public class ShowJavascript {
|
||||||
|
|
||||||
return WebResponseUtils.bytesToWebResponse(
|
return WebResponseUtils.bytesToWebResponse(
|
||||||
script.getBytes(StandardCharsets.UTF_8),
|
script.getBytes(StandardCharsets.UTF_8),
|
||||||
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + ".js");
|
Filenames.toSimpleFileName(inputFile.getOriginalFilename()) + ".js",
|
||||||
|
MediaType.TEXT_PLAIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,6 @@ package stirling.software.SPDF.controller.api.pipeline;
|
||||||
|
|
||||||
public interface UserServiceInterface {
|
public interface UserServiceInterface {
|
||||||
String getApiKeyForUser(String username);
|
String getApiKeyForUser(String username);
|
||||||
|
|
||||||
|
String getCurrentUsername();
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class AccountWebController {
|
||||||
|
|
||||||
Map<String, String> providerList = new HashMap<>();
|
Map<String, String> providerList = new HashMap<>();
|
||||||
|
|
||||||
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
|
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||||
if (oauth != null) {
|
if (oauth != null) {
|
||||||
if (oauth.isSettingsValid()) {
|
if (oauth.isSettingsValid()) {
|
||||||
providerList.put("oidc", oauth.getProvider());
|
providerList.put("oidc", oauth.getProvider());
|
||||||
|
@ -82,7 +82,7 @@ public class AccountWebController {
|
||||||
|
|
||||||
model.addAttribute("loginMethod", applicationProperties.getSecurity().getLoginMethod());
|
model.addAttribute("loginMethod", applicationProperties.getSecurity().getLoginMethod());
|
||||||
model.addAttribute(
|
model.addAttribute(
|
||||||
"oAuth2Enabled", applicationProperties.getSecurity().getOAUTH2().getEnabled());
|
"oAuth2Enabled", applicationProperties.getSecurity().getOauth2().getEnabled());
|
||||||
|
|
||||||
model.addAttribute("currentPage", "login");
|
model.addAttribute("currentPage", "login");
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ public class AccountWebController {
|
||||||
// Retrieve username and other attributes
|
// Retrieve username and other attributes
|
||||||
username =
|
username =
|
||||||
userDetails.getAttribute(
|
userDetails.getAttribute(
|
||||||
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername());
|
applicationProperties.getSecurity().getOauth2().getUseAsUsername());
|
||||||
// Add oAuth2 Login attributes to the model
|
// Add oAuth2 Login attributes to the model
|
||||||
model.addAttribute("oAuth2Login", true);
|
model.addAttribute("oAuth2Login", true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,7 @@ package stirling.software.SPDF.controller.web;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Comparator;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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 org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import io.micrometer.core.instrument.Counter;
|
import io.micrometer.core.instrument.Counter;
|
||||||
import io.micrometer.core.instrument.Meter;
|
|
||||||
import io.micrometer.core.instrument.MeterRegistry;
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.StartupApplicationListener;
|
import stirling.software.SPDF.config.StartupApplicationListener;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/info")
|
@RequestMapping("/api/v1/info")
|
||||||
@Tag(name = "Info", description = "Info APIs")
|
@Tag(name = "Info", description = "Info APIs")
|
||||||
|
@Slf4j
|
||||||
public class MetricsController {
|
public class MetricsController {
|
||||||
|
|
||||||
@Autowired ApplicationProperties applicationProperties;
|
@Autowired ApplicationProperties applicationProperties;
|
||||||
|
@ -46,6 +43,7 @@ public class MetricsController {
|
||||||
this.metricsEnabled = metricsEnabled;
|
this.metricsEnabled = metricsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
public MetricsController(MeterRegistry meterRegistry) {
|
public MetricsController(MeterRegistry meterRegistry) {
|
||||||
this.meterRegistry = meterRegistry;
|
this.meterRegistry = meterRegistry;
|
||||||
}
|
}
|
||||||
|
@ -66,11 +64,11 @@ public class MetricsController {
|
||||||
return ResponseEntity.ok(status);
|
return ResponseEntity.ok(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/loads")
|
@GetMapping("/load")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "GET request count",
|
summary = "GET request count",
|
||||||
description =
|
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(
|
public ResponseEntity<?> getPageLoads(
|
||||||
@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint")
|
@RequestParam(required = false, name = "endpoint") @Parameter(description = "endpoint")
|
||||||
Optional<String> endpoint) {
|
Optional<String> endpoint) {
|
||||||
|
@ -78,44 +76,33 @@ public class MetricsController {
|
||||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
double count = getRequestCount("GET", endpoint);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseEntity.ok(count);
|
return ResponseEntity.ok(count);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
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<String> 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(
|
@Operation(
|
||||||
summary = "GET requests count for all endpoints",
|
summary = "GET requests count for all endpoints",
|
||||||
description = "This endpoint returns the count of GET requests for each endpoint.")
|
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.");
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("This endpoint is disabled.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Map<String, Double> counts = new HashMap<>();
|
List<EndpointCount> results = getEndpointCounts("GET");
|
||||||
|
|
||||||
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<EndpointCount> 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);
|
return ResponseEntity.ok(results);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
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<EndpointCount> 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<String> 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<String> 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<EndpointCount> 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<EndpointCount> results = getUniqueUserCounts("POST");
|
||||||
|
return ResponseEntity.ok(results);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getRequestCount(String method, Optional<String> 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<EndpointCount> getEndpointCounts(String method) {
|
||||||
|
log.info("Getting endpoint counts for method: {}", method);
|
||||||
|
Map<String, Double> 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<EndpointCount> 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<String> endpoint) {
|
||||||
|
log.info(
|
||||||
|
"Getting unique user count for method: {}, endpoint: {}",
|
||||||
|
method,
|
||||||
|
endpoint.orElse("all"));
|
||||||
|
Set<String> 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<EndpointCount> getUniqueUserCounts(String method) {
|
||||||
|
log.info("Getting unique user counts for method: {}", method);
|
||||||
|
Map<String, Set<String>> 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<EndpointCount> 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 String endpoint;
|
||||||
private double count;
|
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<String> 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<String, Double> 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<EndpointCount> 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")
|
@GetMapping("/uptime")
|
||||||
public ResponseEntity<?> getUptime() {
|
public ResponseEntity<?> getUptime() {
|
||||||
if (!metricsEnabled) {
|
if (!metricsEnabled) {
|
||||||
|
|
|
@ -12,6 +12,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
import stirling.software.SPDF.config.YamlPropertySourceFactory;
|
import stirling.software.SPDF.config.YamlPropertySourceFactory;
|
||||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||||
|
@ -21,225 +23,56 @@ import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConfigurationProperties(prefix = "")
|
@ConfigurationProperties(prefix = "")
|
||||||
@PropertySource(value = "file:./configs/settings.yml", factory = YamlPropertySourceFactory.class)
|
@PropertySource(value = "file:./configs/settings.yml", factory = YamlPropertySourceFactory.class)
|
||||||
|
@Data
|
||||||
public class ApplicationProperties {
|
public class ApplicationProperties {
|
||||||
private Security security;
|
|
||||||
private System system;
|
private Legal legal = new Legal();
|
||||||
private Ui ui;
|
private Security security = new Security();
|
||||||
private Endpoints endpoints;
|
private System system = new System();
|
||||||
private Metrics metrics;
|
private Ui ui = new Ui();
|
||||||
private AutomaticallyGenerated automaticallyGenerated;
|
private Endpoints endpoints = new Endpoints();
|
||||||
private AutoPipeline autoPipeline;
|
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);
|
private static final Logger logger = LoggerFactory.getLogger(ApplicationProperties.class);
|
||||||
|
|
||||||
public AutoPipeline getAutoPipeline() {
|
@Data
|
||||||
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
|
|
||||||
+ "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AutoPipeline {
|
public static class AutoPipeline {
|
||||||
private String outputFolder;
|
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 {
|
public static class Security {
|
||||||
private Boolean enableLogin;
|
private Boolean enableLogin;
|
||||||
private Boolean csrfDisabled;
|
private Boolean csrfDisabled;
|
||||||
private InitialLogin initialLogin;
|
private InitialLogin initialLogin = new InitialLogin();
|
||||||
private OAUTH2 oauth2;
|
private OAUTH2 oauth2 = new OAUTH2();
|
||||||
private int loginAttemptCount;
|
private int loginAttemptCount;
|
||||||
private long loginResetTimeMinutes;
|
private long loginResetTimeMinutes;
|
||||||
private String loginMethod = "all";
|
private String loginMethod = "all";
|
||||||
|
|
||||||
public String getLoginMethod() {
|
@Data
|
||||||
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
|
|
||||||
+ "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InitialLogin {
|
public static class InitialLogin {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
@ToString.Exclude 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")
|
|
||||||
+ "]";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
public static class OAUTH2 {
|
public static class OAUTH2 {
|
||||||
private Boolean enabled = false;
|
private Boolean enabled = false;
|
||||||
private String issuer;
|
private String issuer;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private String clientSecret;
|
@ToString.Exclude private String clientSecret;
|
||||||
private Boolean autoCreateUser = false;
|
private Boolean autoCreateUser = false;
|
||||||
private Boolean blockRegistration = false;
|
private Boolean blockRegistration = false;
|
||||||
private String useAsUsername;
|
private String useAsUsername;
|
||||||
|
@ -247,74 +80,6 @@ public class ApplicationProperties {
|
||||||
private String provider;
|
private String provider;
|
||||||
private Client client = new Client();
|
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<String> getScopes() {
|
|
||||||
return scopes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScopes(String scopes) {
|
public void setScopes(String scopes) {
|
||||||
List<String> scopesList =
|
List<String> scopesList =
|
||||||
Arrays.stream(scopes.split(","))
|
Arrays.stream(scopes.split(","))
|
||||||
|
@ -323,26 +88,12 @@ public class ApplicationProperties {
|
||||||
this.scopes.addAll(scopesList);
|
this.scopes.addAll(scopesList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client getClient() {
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClient(Client client) {
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isValid(String value, String name) {
|
protected boolean isValid(String value, String name) {
|
||||||
if (value != null && !value.trim().isEmpty()) {
|
return value != null && !value.trim().isEmpty();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isValid(Collection<String> value, String name) {
|
protected boolean isValid(Collection<String> value, String name) {
|
||||||
if (value != null && !value.isEmpty()) {
|
return value != null && !value.isEmpty();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSettingsValid() {
|
public boolean isSettingsValid() {
|
||||||
|
@ -353,31 +104,7 @@ public class ApplicationProperties {
|
||||||
&& isValid(this.getUseAsUsername(), "useAsUsername");
|
&& isValid(this.getUseAsUsername(), "useAsUsername");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Data
|
||||||
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
|
|
||||||
+ "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Client {
|
public static class Client {
|
||||||
private GoogleProvider google = new GoogleProvider();
|
private GoogleProvider google = new GoogleProvider();
|
||||||
private GithubProvider github = new GithubProvider();
|
private GithubProvider github = new GithubProvider();
|
||||||
|
@ -392,50 +119,15 @@ public class ApplicationProperties {
|
||||||
case "keycloak":
|
case "keycloak":
|
||||||
return getKeycloak();
|
return getKeycloak();
|
||||||
default:
|
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 {
|
public static class System {
|
||||||
private String defaultLocale;
|
private String defaultLocale;
|
||||||
private Boolean googlevisibility;
|
private Boolean googlevisibility;
|
||||||
|
@ -443,184 +135,67 @@ public class ApplicationProperties {
|
||||||
private Boolean showUpdateOnlyAdmin;
|
private Boolean showUpdateOnlyAdmin;
|
||||||
private boolean customHTMLFiles;
|
private boolean customHTMLFiles;
|
||||||
private String tessdataDir;
|
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;
|
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 {
|
public static class Ui {
|
||||||
private String appName;
|
private String appName;
|
||||||
private String homeDescription;
|
private String homeDescription;
|
||||||
private String appNameNavbar;
|
private String appNameNavbar;
|
||||||
|
|
||||||
public String getAppName() {
|
public String getAppName() {
|
||||||
if (appName != null && appName.trim().length() == 0) return null;
|
return appName != null && appName.trim().length() > 0 ? appName : null;
|
||||||
return appName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAppName(String appName) {
|
|
||||||
this.appName = appName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHomeDescription() {
|
public String getHomeDescription() {
|
||||||
if (homeDescription != null && homeDescription.trim().length() == 0) return null;
|
return homeDescription != null && homeDescription.trim().length() > 0
|
||||||
return homeDescription;
|
? homeDescription
|
||||||
}
|
: null;
|
||||||
|
|
||||||
public void setHomeDescription(String homeDescription) {
|
|
||||||
this.homeDescription = homeDescription;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAppNameNavbar() {
|
public String getAppNameNavbar() {
|
||||||
if (appNameNavbar != null && appNameNavbar.trim().length() == 0) return null;
|
return appNameNavbar != null && appNameNavbar.trim().length() > 0
|
||||||
return appNameNavbar;
|
? appNameNavbar
|
||||||
}
|
: null;
|
||||||
|
|
||||||
public void setAppNameNavbar(String appNameNavbar) {
|
|
||||||
this.appNameNavbar = appNameNavbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "UserInterface [appName="
|
|
||||||
+ appName
|
|
||||||
+ ", homeDescription="
|
|
||||||
+ homeDescription
|
|
||||||
+ ", appNameNavbar="
|
|
||||||
+ appNameNavbar
|
|
||||||
+ "]";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
public static class Endpoints {
|
public static class Endpoints {
|
||||||
private List<String> toRemove;
|
private List<String> toRemove;
|
||||||
private List<String> groupsToRemove;
|
private List<String> groupsToRemove;
|
||||||
|
|
||||||
public List<String> getToRemove() {
|
|
||||||
return toRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setToRemove(List<String> toRemove) {
|
|
||||||
this.toRemove = toRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getGroupsToRemove() {
|
|
||||||
return groupsToRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGroupsToRemove(List<String> groupsToRemove) {
|
|
||||||
this.groupsToRemove = groupsToRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Endpoints [toRemove=" + toRemove + ", groupsToRemove=" + groupsToRemove + "]";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
public static class Metrics {
|
public static class Metrics {
|
||||||
private Boolean enabled;
|
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 {
|
public static class AutomaticallyGenerated {
|
||||||
private String key;
|
@ToString.Exclude private String key;
|
||||||
|
}
|
||||||
|
|
||||||
public String getKey() {
|
@Data
|
||||||
return key;
|
public static class EnterpriseEdition {
|
||||||
}
|
@ToString.Exclude private String key;
|
||||||
|
private CustomMetadata customMetadata = new CustomMetadata();
|
||||||
|
|
||||||
public void setKey(String key) {
|
@Data
|
||||||
this.key = key;
|
public static class CustomMetadata {
|
||||||
}
|
private boolean autoUpdateMetadata;
|
||||||
|
private String author;
|
||||||
|
private String creator;
|
||||||
|
private String producer;
|
||||||
|
|
||||||
@Override
|
public String getCreator() {
|
||||||
public String toString() {
|
return creator == null || creator.trim().isEmpty() ? "Stirling-PDF" : creator;
|
||||||
return "AutomaticallyGenerated [key="
|
}
|
||||||
+ (key != null && !key.isEmpty() ? "MASKED" : "NULL")
|
|
||||||
+ "]";
|
public String getProducer() {
|
||||||
|
return producer == null || producer.trim().isEmpty() ? "Stirling-PDF" : producer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ public interface UserRepository extends JpaRepository<User, Long> {
|
||||||
@Query("FROM User u LEFT JOIN FETCH u.settings where upper(u.username) = upper(:username)")
|
@Query("FROM User u LEFT JOIN FETCH u.settings where upper(u.username) = upper(:username)")
|
||||||
Optional<User> findByUsernameIgnoreCaseWithSettings(@Param("username") String username);
|
Optional<User> findByUsernameIgnoreCaseWithSettings(@Param("username") String username);
|
||||||
|
|
||||||
|
|
||||||
Optional<User> findByUsername(String username);
|
Optional<User> findByUsername(String username);
|
||||||
|
|
||||||
Optional<User> findByApiKey(String apiKey);
|
Optional<User> findByApiKey(String apiKey);
|
||||||
|
|
|
@ -6,7 +6,6 @@ import java.awt.image.RenderedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
@ -37,8 +36,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import io.github.pixee.security.Filenames;
|
import io.github.pixee.security.Filenames;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.PdfMetadata;
|
|
||||||
|
|
||||||
public class PdfUtils {
|
public class PdfUtils {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
|
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
|
||||||
|
@ -506,30 +503,6 @@ public class PdfUtils {
|
||||||
return baos.toByteArray();
|
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. */
|
/** Key for storing the dimensions of a rendered image in a map. */
|
||||||
private record PdfRenderSettingsKey(float mediaBoxWidth, float mediaBoxHeight, int rotation) {}
|
private record PdfRenderSettingsKey(float mediaBoxWidth, float mediaBoxHeight, int rotation) {}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ public class RequestUriUtils {
|
||||||
return requestURI.startsWith(contextPath + "/css/")
|
return requestURI.startsWith(contextPath + "/css/")
|
||||||
|| requestURI.startsWith(contextPath + "/fonts/")
|
|| requestURI.startsWith(contextPath + "/fonts/")
|
||||||
|| requestURI.startsWith(contextPath + "/js/")
|
|| requestURI.startsWith(contextPath + "/js/")
|
||||||
|
|| requestURI.endsWith(contextPath + "robots.txt")
|
||||||
|| requestURI.startsWith(contextPath + "/images/")
|
|| requestURI.startsWith(contextPath + "/images/")
|
||||||
|| requestURI.startsWith(contextPath + "/public/")
|
|| requestURI.startsWith(contextPath + "/public/")
|
||||||
|| requestURI.startsWith(contextPath + "/pdfjs/")
|
|| requestURI.startsWith(contextPath + "/pdfjs/")
|
||||||
|
@ -22,4 +23,26 @@ public class RequestUriUtils {
|
||||||
|| requestURI.endsWith(".webmanifest")
|
|| requestURI.endsWith(".webmanifest")
|
||||||
|| requestURI.startsWith(contextPath + "/api/v1/info/status");
|
|| 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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,11 @@ 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 #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Цвят
|
||||||
sponsor=Спонсор
|
sponsor=Спонсор
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Barva
|
||||||
sponsor=Sponzor
|
sponsor=Sponzor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Farve
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Farbe
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Informationen
|
info=Informationen
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Χρώμα
|
||||||
sponsor=Yποστηρικτής
|
sponsor=Yποστηρικτής
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Patrocinador
|
sponsor=Patrocinador
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Couleur
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Dath
|
||||||
sponsor=Urraitheoir
|
sponsor=Urraitheoir
|
||||||
info=Eolas
|
info=Eolas
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Boja
|
||||||
sponsor=Sponzor
|
sponsor=Sponzor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Colore
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=色
|
||||||
sponsor=スポンサー
|
sponsor=スポンサー
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=색상
|
||||||
sponsor=스폰서
|
sponsor=스폰서
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Kleur
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Farge
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=kolor
|
||||||
sponsor=sponsor
|
sponsor=sponsor
|
||||||
info=informacje
|
info=informacje
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Cor
|
||||||
sponsor=Patrocine
|
sponsor=Patrocine
|
||||||
info=Informações
|
info=Informações
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Culoare
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Informații
|
info=Informații
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Цвет
|
||||||
sponsor=Спонсор
|
sponsor=Спонсор
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Farba
|
||||||
sponsor=Sponzorovať
|
sponsor=Sponzorovať
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Color
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Färg
|
||||||
sponsor=Sponsor
|
sponsor=Sponsor
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ 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 #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Renk
|
||||||
sponsor=Bağış
|
sponsor=Bağış
|
||||||
info=Bilgi
|
info=Bilgi
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ 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 #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=Màu sắc
|
||||||
sponsor=Nhà tài trợ
|
sponsor=Nhà tài trợ
|
||||||
info=Thông tin
|
info=Thông tin
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ 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 #
|
# Pipeline #
|
||||||
|
|
|
@ -77,7 +77,11 @@ color=顏色
|
||||||
sponsor=贊助
|
sponsor=贊助
|
||||||
info=Info
|
info=Info
|
||||||
|
|
||||||
|
legal.privacy=Privacy Policy
|
||||||
|
legal.terms=Terms and Conditions
|
||||||
|
legal.accessibility=Accessibility
|
||||||
|
legal.cookie=Cookie Policy
|
||||||
|
legal.impressum=Impressum
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# Pipeline #
|
# Pipeline #
|
||||||
|
|
|
@ -48,6 +48,22 @@ security:
|
||||||
scopes: openid, profile, email # Specify the scopes for which the application will request permissions
|
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'
|
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:
|
system:
|
||||||
defaultLocale: en-US # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
|
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
|
googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
|
||||||
|
|
|
@ -446,7 +446,7 @@ function detectImageType(uint8Array) {
|
||||||
|
|
||||||
// Check for TIFF signature (little-endian and big-endian)
|
// Check for TIFF signature (little-endian and big-endian)
|
||||||
if ((uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) ||
|
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';
|
return 'TIFF';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<!-- jQuery -->
|
<!-- jQuery -->
|
||||||
<script th:src="@{'/js/thirdParty/jquery.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/jquery.min.js'}"></script>
|
||||||
<script th:src="@{'/js/thirdParty/jquery.validate.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/jquery.validate.min.js'}"></script>
|
||||||
<script th:src="@{'/js/thirdParty/jszip.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/jszip.min.js'}" th:if="${currentPage != 'home'}"></script>
|
||||||
|
|
||||||
<!-- Bootstrap -->
|
<!-- Bootstrap -->
|
||||||
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
||||||
|
@ -35,10 +35,10 @@
|
||||||
<link rel="stylesheet" th:href="@{'/css/bootstrap-icons.min.css'}">
|
<link rel="stylesheet" th:href="@{'/css/bootstrap-icons.min.css'}">
|
||||||
|
|
||||||
<!-- PDF.js -->
|
<!-- PDF.js -->
|
||||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}" th:if="${currentPage != 'home'}"></script>
|
||||||
|
|
||||||
<!-- PDF-Lib -->
|
<!-- PDF-Lib -->
|
||||||
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}" th:if="${currentPage != 'home'}"></script>
|
||||||
|
|
||||||
<!-- Custom -->
|
<!-- Custom -->
|
||||||
<link rel="stylesheet" th:href="@{'/css/general.css'}">
|
<link rel="stylesheet" th:href="@{'/css/general.css'}">
|
||||||
|
@ -58,17 +58,21 @@
|
||||||
<link rel="stylesheet" th:href="@{'/css/multi-tool.css'}" th:if="${currentPage == 'multi-tool'}">
|
<link rel="stylesheet" th:href="@{'/css/multi-tool.css'}" th:if="${currentPage == 'multi-tool'}">
|
||||||
<link rel="stylesheet" th:href="@{'/css/rotate-pdf.css'}" th:if="${currentPage == 'rotate-pdf'}">
|
<link rel="stylesheet" th:href="@{'/css/rotate-pdf.css'}" th:if="${currentPage == 'rotate-pdf'}">
|
||||||
<link rel="stylesheet" th:href="@{'/css/stamp.css'}" th:if="${currentPage == 'stamp'}">
|
<link rel="stylesheet" th:href="@{'/css/stamp.css'}" th:if="${currentPage == 'stamp'}">
|
||||||
<link rel="stylesheet" th:href="@{'/css/fileSelect.css'}">
|
<link rel="stylesheet" th:href="@{'/css/fileSelect.css'}" th:if="${currentPage != 'home'}">
|
||||||
<link rel="stylesheet" th:href="@{'/css/footer.css'}">
|
<link rel="stylesheet" th:href="@{'/css/footer.css'}">
|
||||||
|
|
||||||
|
<link rel="preload" href="/fonts/google-symbol.woff2" as="font" type="font/woff2" crossorigin="anonymous">
|
||||||
|
|
||||||
|
|
||||||
<script th:src="@{'/js/thirdParty/fontfaceobserver.standalone.js'}"></script>
|
<script th:src="@{'/js/thirdParty/fontfaceobserver.standalone.js'}"></script>
|
||||||
|
|
||||||
<!-- Google MD Icons -->
|
<!-- Google MD Icons -->
|
||||||
<link rel="stylesheet" th:href="@{'/css/theme/font.css'}">
|
<link rel="stylesheet" th:href="@{'/css/theme/font.css'}">
|
||||||
|
|
||||||
<!-- Help Modal -->
|
<!-- Help Modal -->
|
||||||
<link rel="stylesheet" th:href="@{'/css/errorBanner.css'}">
|
<link rel="stylesheet" th:href="@{'/css/errorBanner.css'}" th:if="${currentPage != 'home'}">
|
||||||
|
|
||||||
<script th:src="@{'/js/cacheFormInputs.js'}"></script>
|
<script th:src="@{'/js/cacheFormInputs.js'}" th:if="${currentPage != 'home'}"></script>
|
||||||
<script th:src="@{'/js/tab-container.js'}"></script>
|
<script th:src="@{'/js/tab-container.js'}"></script>
|
||||||
<script th:src="@{'/js/darkmode.js'}"></script>
|
<script th:src="@{'/js/darkmode.js'}"></script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
<ul class="list-unstyled d-flex">
|
<ul class="list-unstyled d-flex">
|
||||||
<li><a class="footer-link px-2" id="licenses" target="_blank" th:href="@{'/licenses'}" th:text="#{licenses.nav}">Licenses</a></li>
|
<li><a class="footer-link px-2" id="licenses" target="_blank" th:href="@{'/licenses'}" th:text="#{licenses.nav}">Licenses</a></li>
|
||||||
<li><a class="footer-link px-2" id="survey" target="_blank" href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" th:text="#{survey.nav}">Survey</a></li>
|
<li><a class="footer-link px-2" id="survey" target="_blank" href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" th:text="#{survey.nav}">Survey</a></li>
|
||||||
|
<li th:if="${@privacyPolicy != ''}"><a class="footer-link px-2" target="_blank" th:href="${@privacyPolicy}" th:text="#{legal.privacy}">privacyPolicy</a></li>
|
||||||
|
<li th:if="${@termsAndConditions != ''}"><a class="footer-link px-2" target="_blank" th:href="${@termsAndConditions}" th:text="#{legal.terms}">termsAndConditions</a></li>
|
||||||
|
<li th:if="${@accessibilityStatement != ''}"><a class="footer-link px-2" target="_blank" th:href="${@accessibilityStatement}" th:text="#{legal.accessibility}">accessibilityStatement</a></li>
|
||||||
|
<li th:if="${@cookiePolicy != ''}"><a class="footer-link px-2" target="_blank" th:href="${@cookiePolicy}" th:text="#{legal.cookie}">cookiePolicy</a></li>
|
||||||
|
<li th:if="${@impressum != ''}"><a class="footer-link px-2" target="_blank" th:href="${@impressum}" th:text="#{legal.impressum}">impressum</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -94,10 +94,9 @@
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="fontType" th:text="#{addPageNumbers.fontName}"></label>
|
<label for="fontType" th:text="#{addPageNumbers.fontName}"></label>
|
||||||
<select class="form-control" id="fontType" name="fontType">
|
<select class="form-control" id="fontType" name="fontType">
|
||||||
<option value="Times Roman">Times</option>
|
<option value="Times">Times Roman</option>
|
||||||
|
|
||||||
<option value="Helvetica">Helvetica</option>
|
<option value="Helvetica">Helvetica</option>
|
||||||
<option value="Courier New">Courier</option>
|
<option value="Courier">Courier New</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
|
|
@ -110,4 +110,4 @@
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -49,12 +49,5 @@ public class PdfUtilsTest {
|
||||||
assertTrue(PdfUtils.hasImagesOnPage(page));
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue