Cleanups and making distinction between pro and enterprise (#3250)

# Description of Changes

Please provide a summary of the changes, including:

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

Closes #(issue_number)

---

## Checklist

### General

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

### Documentation

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

### UI Changes (if applicable)

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

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: a <a>
This commit is contained in:
Anthony Stirling 2025-03-27 12:42:45 +00:00 committed by GitHub
parent 989c468db2
commit 3420a8633b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 127 additions and 122 deletions

View File

@ -25,7 +25,7 @@ ext {
} }
group = "stirling.software" group = "stirling.software"
version = "0.45.0" version = "0.45.1"
java { java {
// 17 is lowest but we support and recommend 21 // 17 is lowest but we support and recommend 21

View File

@ -7,6 +7,7 @@ import org.springframework.core.annotation.Order;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition; import stirling.software.SPDF.model.ApplicationProperties.EnterpriseEdition;
import stirling.software.SPDF.model.ApplicationProperties.Premium; import stirling.software.SPDF.model.ApplicationProperties.Premium;
@ -27,9 +28,14 @@ public class EEAppConfig {
migrateEnterpriseSettingsToPremium(this.applicationProperties); migrateEnterpriseSettingsToPremium(this.applicationProperties);
} }
@Bean(name = "runningProOrHigher")
public boolean runningProOrHigher() {
return licenseKeyChecker.getPremiumLicenseEnabledResult() != License.NORMAL;
}
@Bean(name = "runningEE") @Bean(name = "runningEE")
public boolean runningEnterpriseEdition() { public boolean runningEnterprise() {
return licenseKeyChecker.getEnterpriseEnabledResult(); return licenseKeyChecker.getPremiumLicenseEnabledResult() == License.ENTERPRISE;
} }
@Bean(name = "SSOAutoLogin") @Bean(name = "SSOAutoLogin")

View File

@ -25,6 +25,13 @@ import stirling.software.SPDF.utils.GeneralUtils;
@Service @Service
@Slf4j @Slf4j
public class KeygenLicenseVerifier { public class KeygenLicenseVerifier {
enum License {
NORMAL,
PRO,
ENTERPRISE
}
// License verification configuration // License verification configuration
private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372"; private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372";
private static final String BASE_URL = "https://api.keygen.sh/v1/accounts"; private static final String BASE_URL = "https://api.keygen.sh/v1/accounts";
@ -45,19 +52,26 @@ public class KeygenLicenseVerifier {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
} }
public boolean verifyLicense(String licenseKeyOrCert) { public License verifyLicense(String licenseKeyOrCert) {
if (isCertificateLicense(licenseKeyOrCert)) { if (isCertificateLicense(licenseKeyOrCert)) {
log.info("Detected certificate-based license. Processing..."); log.info("Detected certificate-based license. Processing...");
return verifyCertificateLicense(licenseKeyOrCert); return resultToEnum(verifyCertificateLicense(licenseKeyOrCert), License.ENTERPRISE);
} else if (isJWTLicense(licenseKeyOrCert)) { } else if (isJWTLicense(licenseKeyOrCert)) {
log.info("Detected JWT-style license key. Processing..."); log.info("Detected JWT-style license key. Processing...");
return verifyJWTLicense(licenseKeyOrCert); return resultToEnum(verifyJWTLicense(licenseKeyOrCert), License.ENTERPRISE);
} else { } else {
log.info("Detected standard license key. Processing..."); log.info("Detected standard license key. Processing...");
return verifyStandardLicense(licenseKeyOrCert); return resultToEnum(verifyStandardLicense(licenseKeyOrCert), License.PRO);
} }
} }
private License resultToEnum(boolean result, License option) {
if (result) {
return option;
}
return License.NORMAL;
}
private boolean isCertificateLicense(String license) { private boolean isCertificateLicense(String license) {
return license != null && license.trim().startsWith(CERT_PREFIX); return license != null && license.trim().startsWith(CERT_PREFIX);
} }

View File

@ -11,6 +11,7 @@ import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.EE.KeygenLicenseVerifier.License;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.GeneralUtils; import stirling.software.SPDF.utils.GeneralUtils;
@ -24,7 +25,7 @@ public class LicenseKeyChecker {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private boolean premiumEnabledResult = false; private License premiumEnabledResult = License.NORMAL;
@Autowired @Autowired
public LicenseKeyChecker( public LicenseKeyChecker(
@ -41,19 +42,21 @@ public class LicenseKeyChecker {
private void checkLicense() { private void checkLicense() {
if (!applicationProperties.getPremium().isEnabled()) { if (!applicationProperties.getPremium().isEnabled()) {
premiumEnabledResult = false; premiumEnabledResult = License.NORMAL;
} else { } else {
String licenseKey = getLicenseKeyContent(applicationProperties.getPremium().getKey()); String licenseKey = getLicenseKeyContent(applicationProperties.getPremium().getKey());
if (licenseKey != null) { if (licenseKey != null) {
premiumEnabledResult = licenseService.verifyLicense(licenseKey); premiumEnabledResult = licenseService.verifyLicense(licenseKey);
if (premiumEnabledResult) { if (License.ENTERPRISE == premiumEnabledResult) {
log.info("License key is valid."); log.info("License key is Enterprise.");
} else if (License.PRO == premiumEnabledResult) {
log.info("License key is Pro.");
} else { } else {
log.info("License key is invalid."); log.info("License key is invalid, defaulting to non pro license.");
} }
} else { } else {
log.error("Failed to obtain license key content."); log.error("Failed to obtain license key content.");
premiumEnabledResult = false; premiumEnabledResult = License.NORMAL;
} }
} }
} }
@ -91,7 +94,7 @@ public class LicenseKeyChecker {
checkLicense(); checkLicense();
} }
public boolean getEnterpriseEnabledResult() { public License getPremiumLicenseEnabledResult() {
return premiumEnabledResult; return premiumEnabledResult;
} }
} }

View File

@ -5,7 +5,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
@ -23,14 +22,14 @@ public class EndpointConfiguration {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>(); private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>(); private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
private final boolean runningEE; private final boolean runningProOrHigher;
@Autowired @Autowired
public EndpointConfiguration( public EndpointConfiguration(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Qualifier("runningEE") boolean runningEE) { @Qualifier("runningProOrHigher") boolean runningProOrHigher) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.runningEE = runningEE; this.runningProOrHigher = runningProOrHigher;
init(); init();
processEnvironmentConfigs(); processEnvironmentConfigs();
} }
@ -98,7 +97,7 @@ public class EndpointConfiguration {
// is false) // is false)
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.sorted() .sorted()
.collect(Collectors.toList()); .toList();
if (!disabledList.isEmpty()) { if (!disabledList.isEmpty()) {
log.info( log.info(
@ -286,7 +285,7 @@ public class EndpointConfiguration {
} }
} }
} }
if (!runningEE) { if (!runningProOrHigher) {
disableGroup("enterprise"); disableGroup("enterprise");
} }

View File

@ -14,10 +14,10 @@ import jakarta.servlet.http.HttpServletResponse;
@Component @Component
public class EnterpriseEndpointFilter extends OncePerRequestFilter { public class EnterpriseEndpointFilter extends OncePerRequestFilter {
private final boolean runningEE; private final boolean runningProOrHigher;
public EnterpriseEndpointFilter(@Qualifier("runningEE") boolean runningEE) { public EnterpriseEndpointFilter(@Qualifier("runningProOrHigher") boolean runningProOrHigher) {
this.runningEE = runningEE; this.runningProOrHigher = runningProOrHigher;
} }
@Override @Override
@ -25,7 +25,7 @@ public class EnterpriseEndpointFilter extends OncePerRequestFilter {
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
if (!runningEE && isPrometheusEndpointRequest(request)) { if (!runningProOrHigher && isPrometheusEndpointRequest(request)) {
response.setStatus(HttpStatus.NOT_FOUND.value()); response.setStatus(HttpStatus.NOT_FOUND.value());
return; return;
} }

View File

@ -62,7 +62,7 @@ public class ExternalAppDepConfig {
private List<String> getAffectedFeatures(String group) { private List<String> getAffectedFeatures(String group) {
return endpointConfiguration.getEndpointsForGroup(group).stream() return endpointConfiguration.getEndpointsForGroup(group).stream()
.map(endpoint -> formatEndpointAsFeature(endpoint)) .map(endpoint -> formatEndpointAsFeature(endpoint))
.collect(Collectors.toList()); .toList();
} }
private String formatEndpointAsFeature(String endpoint) { private String formatEndpointAsFeature(String endpoint) {

View File

@ -2,7 +2,6 @@ package stirling.software.SPDF.config.security;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@ -58,6 +57,6 @@ public class CustomUserDetailsService implements UserDetailsService {
private Collection<? extends GrantedAuthority> getAuthorities(Set<Authority> authorities) { private Collection<? extends GrantedAuthority> getAuthorities(Set<Authority> authorities) {
return authorities.stream() return authorities.stream()
.map(authority -> new SimpleGrantedAuthority(authority.getAuthority())) .map(authority -> new SimpleGrantedAuthority(authority.getAuthority()))
.collect(Collectors.toList()); .toList();
} }
} }

View File

@ -46,13 +46,13 @@ import stirling.software.SPDF.repository.PersistentLoginRepository;
@EnableWebSecurity @EnableWebSecurity
@EnableMethodSecurity @EnableMethodSecurity
@Slf4j @Slf4j
@DependsOn("runningEE") @DependsOn("runningProOrHigher")
public class SecurityConfiguration { public class SecurityConfiguration {
private final CustomUserDetailsService userDetailsService; private final CustomUserDetailsService userDetailsService;
private final UserService userService; private final UserService userService;
private final boolean loginEnabledValue; private final boolean loginEnabledValue;
private final boolean runningEE; private final boolean runningProOrHigher;
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final UserAuthenticationFilter userAuthenticationFilter; private final UserAuthenticationFilter userAuthenticationFilter;
@ -69,7 +69,7 @@ public class SecurityConfiguration {
CustomUserDetailsService userDetailsService, CustomUserDetailsService userDetailsService,
@Lazy UserService userService, @Lazy UserService userService,
@Qualifier("loginEnabled") boolean loginEnabledValue, @Qualifier("loginEnabled") boolean loginEnabledValue,
@Qualifier("runningEE") boolean runningEE, @Qualifier("runningProOrHigher") boolean runningProOrHigher,
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
UserAuthenticationFilter userAuthenticationFilter, UserAuthenticationFilter userAuthenticationFilter,
LoginAttemptService loginAttemptService, LoginAttemptService loginAttemptService,
@ -83,7 +83,7 @@ public class SecurityConfiguration {
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
this.userService = userService; this.userService = userService;
this.loginEnabledValue = loginEnabledValue; this.loginEnabledValue = loginEnabledValue;
this.runningEE = runningEE; this.runningProOrHigher = runningProOrHigher;
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.userAuthenticationFilter = userAuthenticationFilter; this.userAuthenticationFilter = userAuthenticationFilter;
this.loginAttemptService = loginAttemptService; this.loginAttemptService = loginAttemptService;
@ -254,7 +254,7 @@ public class SecurityConfiguration {
.permitAll()); .permitAll());
} }
// Handle SAML // Handle SAML
if (applicationProperties.getSecurity().isSaml2Active() && runningEE) { if (applicationProperties.getSecurity().isSaml2Active() && runningProOrHigher) {
// Configure the authentication provider // Configure the authentication provider
OpenSaml4AuthenticationProvider authenticationProvider = OpenSaml4AuthenticationProvider authenticationProvider =
new OpenSaml4AuthenticationProvider(); new OpenSaml4AuthenticationProvider();

View File

@ -3,7 +3,6 @@ package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -99,7 +98,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
authority -> authority ->
new SimpleGrantedAuthority( new SimpleGrantedAuthority(
authority.getAuthority())) authority.getAuthority()))
.collect(Collectors.toList()); .toList();
authentication = new ApiKeyAuthenticationToken(user.get(), apiKey, authorities); authentication = new ApiKeyAuthenticationToken(user.get(), apiKey, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication); SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (AuthenticationException e) { } catch (AuthenticationException e) {

View File

@ -3,7 +3,6 @@ package stirling.software.SPDF.config.security;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
@ -108,7 +107,7 @@ public class UserService implements UserServiceInterface {
// Convert each Authority object into a SimpleGrantedAuthority object. // Convert each Authority object into a SimpleGrantedAuthority object.
return user.getAuthorities().stream() return user.getAuthorities().stream()
.map((Authority authority) -> new SimpleGrantedAuthority(authority.getAuthority())) .map((Authority authority) -> new SimpleGrantedAuthority(authority.getAuthority()))
.collect(Collectors.toList()); .toList();
} }
private String generateApiKey() { private String generateApiKey() {

View File

@ -27,18 +27,18 @@ public class DatabaseConfig {
public static final String POSTGRES_DRIVER = "org.postgresql.Driver"; public static final String POSTGRES_DRIVER = "org.postgresql.Driver";
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final boolean runningEE; private final boolean runningProOrHigher;
public DatabaseConfig( public DatabaseConfig(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Qualifier("runningEE") boolean runningEE) { @Qualifier("runningProOrHigher") boolean runningProOrHigher) {
DATASOURCE_DEFAULT_URL = DATASOURCE_DEFAULT_URL =
"jdbc:h2:file:" "jdbc:h2:file:"
+ InstallationPathConfig.getConfigPath() + InstallationPathConfig.getConfigPath()
+ "stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"; + "stirling-pdf-DB-2.3.232;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE";
log.debug("Database URL: {}", DATASOURCE_DEFAULT_URL); log.debug("Database URL: {}", DATASOURCE_DEFAULT_URL);
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.runningEE = runningEE; this.runningProOrHigher = runningProOrHigher;
} }
/** /**
@ -54,7 +54,7 @@ public class DatabaseConfig {
public DataSource dataSource() throws UnsupportedProviderException { public DataSource dataSource() throws UnsupportedProviderException {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create(); DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
if (!runningEE) { if (!runningProOrHigher) {
return useDefaultDataSource(dataSourceBuilder); return useDefaultDataSource(dataSourceBuilder);
} }

View File

@ -17,7 +17,6 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -170,7 +169,7 @@ public class DatabaseService implements DatabaseInterface {
List<FileInfo> filteredBackupList = List<FileInfo> filteredBackupList =
this.getBackupList().stream() this.getBackupList().stream()
.filter(backup -> !backup.getFileName().startsWith(BACKUP_PREFIX + "user_")) .filter(backup -> !backup.getFileName().startsWith(BACKUP_PREFIX + "user_"))
.collect(Collectors.toList()); .toList();
if (filteredBackupList.size() > 5) { if (filteredBackupList.size() > 5) {
deleteOldestBackup(filteredBackupList); deleteOldestBackup(filteredBackupList);

View File

@ -10,7 +10,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.apache.pdfbox.multipdf.PDFMergerUtility; import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
@ -165,7 +164,7 @@ public class MergeController {
List<PDField> fieldsToRemove = List<PDField> fieldsToRemove =
acroForm.getFields().stream() acroForm.getFields().stream()
.filter(field -> field instanceof PDSignatureField) .filter(field -> field instanceof PDSignatureField)
.collect(Collectors.toList()); .toList();
if (!fieldsToRemove.isEmpty()) { if (!fieldsToRemove.isEmpty()) {
acroForm.flatten( acroForm.flatten(

View File

@ -8,7 +8,6 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -146,7 +145,7 @@ public class ConvertImgPDFController {
List<Path> webpFiles = List<Path> webpFiles =
Files.walk(tempOutputDir) Files.walk(tempOutputDir)
.filter(path -> path.toString().endsWith(".webp")) .filter(path -> path.toString().endsWith(".webp"))
.collect(Collectors.toList()); .toList();
if (webpFiles.isEmpty()) { if (webpFiles.isEmpty()) {
log.error("No WebP files were created in: {}", tempOutputDir.toString()); log.error("No WebP files were created in: {}", tempOutputDir.toString());

View File

@ -5,7 +5,6 @@ import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -63,7 +62,7 @@ public class OCRController {
.filter(file -> file.getName().endsWith(".traineddata")) .filter(file -> file.getName().endsWith(".traineddata"))
.map(file -> file.getName().replace(".traineddata", "")) .map(file -> file.getName().replace(".traineddata", ""))
.filter(lang -> !lang.equalsIgnoreCase("osd")) .filter(lang -> !lang.equalsIgnoreCase("osd"))
.collect(Collectors.toList()); .toList();
} }
@PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf") @PostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")

View File

@ -5,7 +5,6 @@ import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -64,9 +63,7 @@ public class PipelineController {
log.info("Received POST request to /handleData with {} files", files.length); log.info("Received POST request to /handleData with {} files", files.length);
List<String> operationNames = List<String> operationNames =
config.getOperations().stream() config.getOperations().stream().map(PipelineOperation::getOperation).toList();
.map(PipelineOperation::getOperation)
.collect(Collectors.toList());
Map<String, Object> properties = new HashMap<>(); Map<String, Object> properties = new HashMap<>();
properties.put("operations", operationNames); properties.put("operations", operationNames);

View File

@ -11,7 +11,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -168,7 +167,7 @@ public class PipelineProcessor {
file -> file ->
finalinputFileTypes.stream() finalinputFileTypes.stream()
.anyMatch(file.getFilename()::endsWith)) .anyMatch(file.getFilename()::endsWith))
.collect(Collectors.toList()); .toList();
} }
// Check if there are matching files // Check if there are matching files
if (!matchingFiles.isEmpty()) { if (!matchingFiles.isEmpty()) {

View File

@ -1,7 +1,6 @@
package stirling.software.SPDF.controller.api.security; package stirling.software.SPDF.controller.api.security;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
@ -59,7 +58,7 @@ public class RemoveCertSignController {
List<PDField> fieldsToRemove = List<PDField> fieldsToRemove =
acroForm.getFields().stream() acroForm.getFields().stream()
.filter(field -> field instanceof PDSignatureField) .filter(field -> field instanceof PDSignatureField)
.collect(Collectors.toList()); .toList();
if (!fieldsToRemove.isEmpty()) { if (!fieldsToRemove.isEmpty()) {
acroForm.flatten(fieldsToRemove, false); acroForm.flatten(fieldsToRemove, false);

View File

@ -66,13 +66,13 @@ public class SanitizeController {
} }
if (removeXMPMetadata) { if (removeXMPMetadata) {
sanitizeXMPMetadata(document); sanitizeXMPMetadata(document);
} }
if (removeMetadata) { if (removeMetadata) {
sanitizeDocumentInfoMetadata(document); sanitizeDocumentInfoMetadata(document);
} }
if (removeLinks) { if (removeLinks) {
sanitizeLinks(document); sanitizeLinks(document);
} }
@ -158,7 +158,7 @@ public class SanitizeController {
} }
} }
} }
private void sanitizeDocumentInfoMetadata(PDDocument document) { private void sanitizeDocumentInfoMetadata(PDDocument document) {
PDDocumentInformation docInfo = document.getDocumentInformation(); PDDocumentInformation docInfo = document.getDocumentInformation();
if (docInfo != null) { if (docInfo != null) {
@ -167,8 +167,6 @@ public class SanitizeController {
} }
} }
private void sanitizeLinks(PDDocument document) throws IOException { private void sanitizeLinks(PDDocument document) throws IOException {
for (PDPage page : document.getPages()) { for (PDPage page : document.getPages()) {
for (PDAnnotation annotation : page.getAnnotations()) { for (PDAnnotation annotation : page.getAnnotations()) {

View File

@ -10,8 +10,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@ -56,14 +56,17 @@ public class AccountWebController {
private final SessionPersistentRegistry sessionPersistentRegistry; private final SessionPersistentRegistry sessionPersistentRegistry;
// Assuming you have a repository for user operations // Assuming you have a repository for user operations
private final UserRepository userRepository; private final UserRepository userRepository;
private final boolean runningEE;
public AccountWebController( public AccountWebController(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
SessionPersistentRegistry sessionPersistentRegistry, SessionPersistentRegistry sessionPersistentRegistry,
UserRepository userRepository) { UserRepository userRepository,
@Qualifier("runningEE") boolean runningEE) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.sessionPersistentRegistry = sessionPersistentRegistry; this.sessionPersistentRegistry = sessionPersistentRegistry;
this.userRepository = userRepository; this.userRepository = userRepository;
this.runningEE = runningEE;
} }
@GetMapping("/login") @GetMapping("/login")
@ -197,6 +200,9 @@ public class AccountWebController {
@PreAuthorize("hasRole('ROLE_ADMIN')") @PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/usage") @GetMapping("/usage")
public String showUsage() { public String showUsage() {
if (!runningEE) {
return "error";
}
return "usage"; return "usage";
} }
@ -279,7 +285,7 @@ public class AccountWebController {
return u2LastRequest.compareTo(u1LastRequest); return u2LastRequest.compareTo(u1LastRequest);
} }
}) })
.collect(Collectors.toList()); .toList();
String messageType = request.getParameter("messageType"); String messageType = request.getParameter("messageType");
String deleteMessage; String deleteMessage;
@ -325,7 +331,7 @@ public class AccountWebController {
model.addAttribute("activeUsers", activeUsers); model.addAttribute("activeUsers", activeUsers);
model.addAttribute("disabledUsers", disabledUsers); model.addAttribute("disabledUsers", disabledUsers);
model.addAttribute("maxEnterpriseUsers", applicationProperties.getPremium().getMaxUsers()); model.addAttribute("maxPaidUsers", applicationProperties.getPremium().getMaxUsers());
return "adminSettings"; return "adminSettings";
} }

View File

@ -7,7 +7,6 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -65,7 +64,7 @@ public class GeneralWebController {
List<Path> jsonFiles = List<Path> jsonFiles =
paths.filter(Files::isRegularFile) paths.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json")) .filter(p -> p.toString().endsWith(".json"))
.collect(Collectors.toList()); .toList();
for (Path jsonFile : jsonFiles) { for (Path jsonFile : jsonFiles) {
String content = Files.readString(jsonFile, StandardCharsets.UTF_8); String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
pipelineConfigs.add(content); pipelineConfigs.add(content);
@ -261,7 +260,7 @@ public class GeneralWebController {
} }
}) })
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toList()); .toList();
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Failed to read font directory from " + locationPattern, e); throw new RuntimeException("Failed to read font directory from " + locationPattern, e);
} }

View File

@ -3,7 +3,6 @@ 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.*; import java.util.*;
import java.util.stream.Collectors;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -287,7 +286,7 @@ public class MetricsController {
return counts.entrySet().stream() return counts.entrySet().stream()
.map(entry -> new EndpointCount(entry.getKey(), entry.getValue())) .map(entry -> new EndpointCount(entry.getKey(), entry.getValue()))
.sorted(Comparator.comparing(EndpointCount::getCount).reversed()) .sorted(Comparator.comparing(EndpointCount::getCount).reversed())
.collect(Collectors.toList()); .toList();
} }
private double getUniqueUserCount(String method, Optional<String> endpoint) { private double getUniqueUserCount(String method, Optional<String> endpoint) {
@ -349,7 +348,7 @@ public class MetricsController {
return uniqueUsers.entrySet().stream() return uniqueUsers.entrySet().stream()
.map(entry -> new EndpointCount(entry.getKey(), entry.getValue().size())) .map(entry -> new EndpointCount(entry.getKey(), entry.getValue().size()))
.sorted(Comparator.comparing(EndpointCount::getCount).reversed()) .sorted(Comparator.comparing(EndpointCount::getCount).reversed())
.collect(Collectors.toList()); .toList();
} }
@GetMapping("/uptime") @GetMapping("/uptime")

View File

@ -4,7 +4,6 @@ import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -123,8 +122,8 @@ public class OtherWebController {
return Arrays.stream(files) return Arrays.stream(files)
.filter(file -> file.getName().endsWith(".traineddata")) .filter(file -> file.getName().endsWith(".traineddata"))
.map(file -> file.getName().replace(".traineddata", "")) .map(file -> file.getName().replace(".traineddata", ""))
.filter(lang -> !lang.equalsIgnoreCase("osd")) .filter(lang -> !lang.equalsIgnoreCase("osd")).sorted()
.collect(Collectors.toList()); .toList();
} }
@GetMapping("/ocr-pdf") @GetMapping("/ocr-pdf")
@ -132,7 +131,6 @@ public class OtherWebController {
public ModelAndView ocrPdfPage() { public ModelAndView ocrPdfPage() {
ModelAndView modelAndView = new ModelAndView("misc/ocr-pdf"); ModelAndView modelAndView = new ModelAndView("misc/ocr-pdf");
List<String> languages = getAvailableTesseractLanguages(); List<String> languages = getAvailableTesseractLanguages();
Collections.sort(languages);
modelAndView.addObject("languages", languages); modelAndView.addObject("languages", languages);
modelAndView.addObject("currentPage", "ocr-pdf"); modelAndView.addObject("currentPage", "ocr-pdf");
return modelAndView; return modelAndView;

View File

@ -22,7 +22,7 @@ public class SanitizePdfRequest extends PDFFile {
@Schema(description = "Remove document info metadata from the PDF", defaultValue = "false") @Schema(description = "Remove document info metadata from the PDF", defaultValue = "false")
private boolean removeMetadata; private boolean removeMetadata;
@Schema(description = "Remove links from the PDF", defaultValue = "false") @Schema(description = "Remove links from the PDF", defaultValue = "false")
private boolean removeLinks; private boolean removeLinks;

View File

@ -5,7 +5,6 @@ import static stirling.software.SPDF.model.UsernameAttribute.EMAIL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.stream.Collectors;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -59,8 +58,7 @@ public class Provider {
public void setScopes(String scopes) { public void setScopes(String scopes) {
if (scopes != null && !scopes.isBlank()) { if (scopes != null && !scopes.isBlank()) {
this.scopes = this.scopes = Arrays.stream(scopes.split(",")).map(String::trim).toList();
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
} }
} }

View File

@ -68,17 +68,17 @@ public class CustomPDFDocumentFactory {
} }
/** /**
* Main entry point for loading a PDF document from a file. Automatically selects the most * Main entry point for loading a PDF document from a file. Automatically selects the most
* appropriate loading strategy. * appropriate loading strategy.
*/ */
public PDDocument load(File file) throws IOException { public PDDocument load(File file) throws IOException {
return load(file, false); return load(file, false);
} }
/** /**
* Main entry point for loading a PDF document from a file with read-only option. * Main entry point for loading a PDF document from a file with read-only option. Automatically
* Automatically selects the most appropriate loading strategy. * selects the most appropriate loading strategy.
*/ */
public PDDocument load(File file, boolean readOnly) throws IOException { public PDDocument load(File file, boolean readOnly) throws IOException {
if (file == null) { if (file == null) {
throw new IllegalArgumentException("File cannot be null"); throw new IllegalArgumentException("File cannot be null");
@ -95,17 +95,17 @@ public class CustomPDFDocumentFactory {
} }
/** /**
* Main entry point for loading a PDF document from a Path. Automatically selects the most * Main entry point for loading a PDF document from a Path. Automatically selects the most
* appropriate loading strategy. * appropriate loading strategy.
*/ */
public PDDocument load(Path path) throws IOException { public PDDocument load(Path path) throws IOException {
return load(path, false); return load(path, false);
} }
/** /**
* Main entry point for loading a PDF document from a Path with read-only option. * Main entry point for loading a PDF document from a Path with read-only option. Automatically
* Automatically selects the most appropriate loading strategy. * selects the most appropriate loading strategy.
*/ */
public PDDocument load(Path path, boolean readOnly) throws IOException { public PDDocument load(Path path, boolean readOnly) throws IOException {
if (path == null) { if (path == null) {
throw new IllegalArgumentException("File cannot be null"); throw new IllegalArgumentException("File cannot be null");
@ -170,7 +170,8 @@ public class CustomPDFDocumentFactory {
} }
/** Load with password from InputStream and read-only option */ /** Load with password from InputStream and read-only option */
public PDDocument load(InputStream input, String password, boolean readOnly) throws IOException { public PDDocument load(InputStream input, String password, boolean readOnly)
throws IOException {
if (input == null) { if (input == null) {
throw new IllegalArgumentException("InputStream cannot be null"); throw new IllegalArgumentException("InputStream cannot be null");
} }
@ -179,7 +180,8 @@ public class CustomPDFDocumentFactory {
Path tempFile = createTempFile("pdf-stream-"); Path tempFile = createTempFile("pdf-stream-");
Files.copy(input, tempFile, StandardCopyOption.REPLACE_EXISTING); Files.copy(input, tempFile, StandardCopyOption.REPLACE_EXISTING);
PDDocument doc = loadAdaptivelyWithPassword(tempFile.toFile(), Files.size(tempFile), password); PDDocument doc =
loadAdaptivelyWithPassword(tempFile.toFile(), Files.size(tempFile), password);
if (!readOnly) { if (!readOnly) {
postProcessDocument(doc); postProcessDocument(doc);
} }
@ -203,7 +205,7 @@ public class CustomPDFDocumentFactory {
/** Load from a PDFFile object with read-only option */ /** Load from a PDFFile object with read-only option */
public PDDocument load(PDFFile pdfFile, boolean readOnly) throws IOException { public PDDocument load(PDFFile pdfFile, boolean readOnly) throws IOException {
return load(pdfFile.getFileInput(), readOnly); return load(pdfFile.getFileInput(), readOnly);
} }
/** Load from a MultipartFile */ /** Load from a MultipartFile */
@ -213,8 +215,7 @@ public class CustomPDFDocumentFactory {
/** Load from a MultipartFile with read-only option */ /** Load from a MultipartFile with read-only option */
public PDDocument load(MultipartFile pdfFile, boolean readOnly) throws IOException { public PDDocument load(MultipartFile pdfFile, boolean readOnly) throws IOException {
return load(pdfFile.getInputStream(), readOnly); return load(pdfFile.getInputStream(), readOnly);
} }
/** Load with password from MultipartFile */ /** Load with password from MultipartFile */
@ -223,10 +224,11 @@ public class CustomPDFDocumentFactory {
} }
/** Load with password from MultipartFile with read-only option */ /** Load with password from MultipartFile with read-only option */
public PDDocument load(MultipartFile fileInput, String password, boolean readOnly) throws IOException { public PDDocument load(MultipartFile fileInput, String password, boolean readOnly)
return load(fileInput.getInputStream(), password, readOnly); throws IOException {
return load(fileInput.getInputStream(), password, readOnly);
} }
/** /**
* Determine the appropriate caching strategy based on file size and available memory. This * Determine the appropriate caching strategy based on file size and available memory. This
* common method is used by both password and non-password loading paths. * common method is used by both password and non-password loading paths.
@ -471,5 +473,4 @@ public class CustomPDFDocumentFactory {
return saveToBytes(document); return saveToBytes(document);
} }
} }
} }

View File

@ -17,18 +17,18 @@ public class PdfMetadataService {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final String stirlingPDFLabel; private final String stirlingPDFLabel;
private final UserServiceInterface userService; private final UserServiceInterface userService;
private final boolean runningEE; private final boolean runningProOrHigher;
@Autowired @Autowired
public PdfMetadataService( public PdfMetadataService(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@Qualifier("StirlingPDFLabel") String stirlingPDFLabel, @Qualifier("StirlingPDFLabel") String stirlingPDFLabel,
@Qualifier("runningEE") boolean runningEE, @Qualifier("runningProOrHigher") boolean runningProOrHigher,
@Autowired(required = false) UserServiceInterface userService) { @Autowired(required = false) UserServiceInterface userService) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
this.stirlingPDFLabel = stirlingPDFLabel; this.stirlingPDFLabel = stirlingPDFLabel;
this.userService = userService; this.userService = userService;
this.runningEE = runningEE; this.runningProOrHigher = runningProOrHigher;
} }
public PdfMetadata extractMetadataFromPdf(PDDocument pdf) { public PdfMetadata extractMetadataFromPdf(PDDocument pdf) {
@ -69,7 +69,7 @@ public class PdfMetadataService {
.getProFeatures() .getProFeatures()
.getCustomMetadata() .getCustomMetadata()
.isAutoUpdateMetadata() .isAutoUpdateMetadata()
&& runningEE) { && runningProOrHigher) {
creator = creator =
applicationProperties applicationProperties
@ -98,7 +98,7 @@ public class PdfMetadataService {
.getProFeatures() .getProFeatures()
.getCustomMetadata() .getCustomMetadata()
.isAutoUpdateMetadata() .isAutoUpdateMetadata()
&& runningEE) { && runningProOrHigher) {
author = author =
applicationProperties applicationProperties
.getPremium() .getPremium()

View File

@ -7,7 +7,6 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils; import org.thymeleaf.util.StringUtils;
@ -70,7 +69,7 @@ public class SignatureService {
return Files.list(folder) return Files.list(folder)
.filter(path -> isImageFile(path)) .filter(path -> isImageFile(path))
.map(path -> new SignatureFile(path.getFileName().toString(), category)) .map(path -> new SignatureFile(path.getFileName().toString(), category))
.collect(Collectors.toList()); .toList();
} }
public byte[] getSignatureBytes(String username, String fileName) throws IOException { public byte[] getSignatureBytes(String username, String fileName) throws IOException {

View File

@ -9,7 +9,6 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -172,9 +171,7 @@ public class FileToPdf {
// Search for the main HTML file. // Search for the main HTML file.
try (Stream<Path> walk = Files.walk(tempDirectory)) { try (Stream<Path> walk = Files.walk(tempDirectory)) {
List<Path> htmlFiles = List<Path> htmlFiles = walk.filter(file -> file.toString().endsWith(".html")).toList();
walk.filter(file -> file.toString().endsWith(".html"))
.collect(Collectors.toList());
if (htmlFiles.isEmpty()) { if (htmlFiles.isEmpty()) {
throw new IOException("No HTML files found in the unzipped directory."); throw new IOException("No HTML files found in the unzipped directory.");

View File

@ -34,10 +34,10 @@
<!-- User Settings Title --> <!-- User Settings Title -->
<div style="background: var(--md-sys-color-outline-variant);padding: .8rem; margin: 10px 0; border-radius: 2rem; text-align: center;"> <div style="background: var(--md-sys-color-outline-variant);padding: .8rem; margin: 10px 0; border-radius: 2rem; text-align: center;">
<a href="#" <a href="#"
th:data-bs-toggle="${@runningEE && totalUsers >= maxEnterpriseUsers} ? null : 'modal'" th:data-bs-toggle="${@runningProOrHigher && totalUsers >= maxPaidUsers} ? null : 'modal'"
th:data-bs-target="${@runningEE && totalUsers >= maxEnterpriseUsers} ? null : '#addUserModal'" th:data-bs-target="${@runningProOrHigher && totalUsers >= maxPaidUsers} ? null : '#addUserModal'"
th:class="${@runningEE && totalUsers >= maxEnterpriseUsers} ? 'btn btn-danger' : 'btn btn-outline-success'" th:class="${@runningProOrHigher && totalUsers >= maxPaidUsers} ? 'btn btn-danger' : 'btn btn-outline-success'"
th:title="${@runningEE && totalUsers >= maxEnterpriseUsers} ? #{adminUserSettings.maxUsersReached} : #{adminUserSettings.addUser}"> th:title="${@runningProOrHigher && totalUsers >= maxPaidUsers} ? #{adminUserSettings.maxUsersReached} : #{adminUserSettings.addUser}">
<span class="material-symbols-rounded">person_add</span> <span class="material-symbols-rounded">person_add</span>
<span th:text="#{adminUserSettings.addUser}">Add New User</span> <span th:text="#{adminUserSettings.addUser}">Add New User</span>
</a> </a>
@ -51,7 +51,7 @@
<span th:text="#{adminUserSettings.changeUserRole}">Change User's Role</span> <span th:text="#{adminUserSettings.changeUserRole}">Change User's Role</span>
</a> </a>
<a href="/usage" <a href="/usage" th:if="${@runningEE}"
class="btn btn-outline-success" class="btn btn-outline-success"
th:title="#{adminUserSettings.usage}"> th:title="#{adminUserSettings.usage}">
<span class="material-symbols-rounded">analytics</span> <span class="material-symbols-rounded">analytics</span>
@ -61,7 +61,7 @@
<div class="my-4"> <div class="my-4">
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.totalUsers}">Total Users:</strong> <strong style="margin-left: 20px;" th:text="#{adminUserSettings.totalUsers}">Total Users:</strong>
<span th:text="${totalUsers}"></span> <span th:text="${totalUsers}"></span>
<span th:if="${@runningEE}" th:text="'/'+${maxEnterpriseUsers}"></span> <span th:if="${@runningProOrHigher}" th:text="'/'+${maxPaidUsers}"></span>
<strong style="margin-left: 20px;" th:text="#{adminUserSettings.activeUsers}">Active Users:</strong> <strong style="margin-left: 20px;" th:text="#{adminUserSettings.activeUsers}">Active Users:</strong>
<span th:text="${activeUsers}"></span> <span th:text="${activeUsers}"></span>
@ -126,7 +126,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<p th:if="${!@runningEE}" th:text="#{enterpriseEdition.ssoAdvert}"></p> <p th:if="${!@runningProOrHigher}" th:text="#{enterpriseEdition.ssoAdvert}"></p>
<script th:inline="javascript"> <script th:inline="javascript">
const delete_confirm_text = /*[[#{adminUserSettings.confirmDeleteUser}]]*/ 'Should the user be deleted?'; const delete_confirm_text = /*[[#{adminUserSettings.confirmDeleteUser}]]*/ 'Should the user be deleted?';

View File

@ -170,7 +170,7 @@
</div> </div>
</li> </li>
<li class="nav-item" th:if="${!@runningEE}"> <li class="nav-item" th:if="${!@runningProOrHigher}">
<a href="https://stirlingpdf.com/pricing" class="nav-link go-pro-link" target="_blank" <a href="https://stirlingpdf.com/pricing" class="nav-link go-pro-link" target="_blank"
rel="noopener noreferrer"> rel="noopener noreferrer">
<span class="go-pro-badge" th:text="#{enterpriseEdition.button}"></span> <span class="go-pro-badge" th:text="#{enterpriseEdition.button}"></span>

View File

@ -39,7 +39,7 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const runningEE = /*[[${@runningEE}]]*/ false; const runningProOrHigher = /*[[${@runningProOrHigher}]]*/ false;
const SSOAutoLogin = /*[[${@SSOAutoLogin}]]*/ false; const SSOAutoLogin = /*[[${@SSOAutoLogin}]]*/ false;
const loginMethod = /*[[${loginMethod}]]*/ 'normal'; const loginMethod = /*[[${loginMethod}]]*/ 'normal';
const providerList = /*[[${providerList}]]*/ {}; const providerList = /*[[${providerList}]]*/ {};
@ -47,7 +47,7 @@
!hasLogout && !hasLogout &&
!hasMessage && !hasMessage &&
redirectAttempts < MAX_REDIRECT_ATTEMPTS && redirectAttempts < MAX_REDIRECT_ATTEMPTS &&
loginMethod !== 'normal' && runningEE && SSOAutoLogin; loginMethod !== 'normal' && runningProOrHigher && SSOAutoLogin;
console.log('Should redirect:', shouldAutoRedirect, { console.log('Should redirect:', shouldAutoRedirect, {
'No error': !hasRedirectError, 'No error': !hasRedirectError,