diff --git a/src/main/java/stirling/software/SPDF/config/AppConfig.java b/src/main/java/stirling/software/SPDF/config/AppConfig.java new file mode 100644 index 000000000..feb6b66b2 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/AppConfig.java @@ -0,0 +1,235 @@ +package stirling.software.SPDF.config; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Properties; +import java.util.function.Predicate; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Scope; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.thymeleaf.spring6.SpringTemplateEngine; + +import com.posthog.java.shaded.kotlin.text.Regex; + +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.model.ApplicationProperties; + +@Configuration +@Lazy +@Slf4j +public class AppConfig { + + private final ApplicationProperties applicationProperties; + + public AppConfig(ApplicationProperties applicationProperties) { + this.applicationProperties = applicationProperties; + } + + @Bean + @ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true") + public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader)); + return templateEngine; + } + + @Bean(name = "loginEnabled") + public boolean loginEnabled() { + return applicationProperties.getSecurity().getEnableLogin(); + } + + @Bean(name = "appName") + public String appName() { + String homeTitle = applicationProperties.getUi().getAppName(); + return (homeTitle != null) ? homeTitle : "Stirling PDF"; + } + + @Bean(name = "appVersion") + public String appVersion() { + Resource resource = new ClassPathResource("version.properties"); + Properties props = new Properties(); + try { + props.load(resource.getInputStream()); + return props.getProperty("version"); + } catch (IOException e) { + log.error("exception", e); + } + return "0.0.0"; + } + + @Bean(name = "homeText") + public String homeText() { + return (applicationProperties.getUi().getHomeDescription() != null) + ? applicationProperties.getUi().getHomeDescription() + : "null"; + } + + @Bean(name = "languages") + public List languages() { + return applicationProperties.getUi().getLanguages(); + } + + @Bean + public String contextPath(@Value("${server.servlet.context-path}") String contextPath) { + return contextPath; + } + + @Bean(name = "navBarText") + public String navBarText() { + String defaultNavBar = + applicationProperties.getUi().getAppNameNavbar() != null + ? applicationProperties.getUi().getAppNameNavbar() + : applicationProperties.getUi().getAppName(); + return (defaultNavBar != null) ? defaultNavBar : "Stirling PDF"; + } + + @Bean(name = "enableAlphaFunctionality") + public boolean enableAlphaFunctionality() { + return applicationProperties.getSystem().getEnableAlphaFunctionality() != null + ? applicationProperties.getSystem().getEnableAlphaFunctionality() + : false; + } + + @Bean(name = "rateLimit") + public boolean rateLimit() { + String rateLimit = System.getProperty("rateLimit"); + if (rateLimit == null) rateLimit = System.getenv("rateLimit"); + return (rateLimit != null) ? Boolean.valueOf(rateLimit) : false; + } + + @Bean(name = "uploadLimit") + public long uploadLimit() { + boolean uploadLimit = + applicationProperties.getSystem().getUploadLimit().getEnableUploadSizeLimit() + != null + ? applicationProperties + .getSystem() + .getUploadLimit() + .getEnableUploadSizeLimit() + : false; + if (!uploadLimit) { + return 0; + } + String maxUploadSize = applicationProperties.getSystem().getUploadLimit().getLimit(); + if (!new Regex("^[1-9][0-9]{0,2}[K|M|G]B$").matches(maxUploadSize)) { + log.error( + "Invalid maxUploadSize format. Expected format: {1,3}[0-9][K|M|G]B, but got: {}", + maxUploadSize); + return 1; + } + if (maxUploadSize == null || maxUploadSize.isEmpty()) { + return 2; + } else { + String unit = maxUploadSize.replaceAll("[1-9][0-9]{0,2}", ""); + String number = maxUploadSize.replaceAll("[K|M|G]B", ""); + long size = Long.parseLong(number); + return switch (unit) { + case "KB" -> size * 1024; + case "MB" -> size * 1024 * 1024; + case "GB" -> size * 1024 * 1024 * 1024; + default -> size; + }; + } + } + + @Bean(name = "RunningInDocker") + public boolean runningInDocker() { + return Files.exists(Paths.get("/.dockerenv")); + } + + @Bean(name = "configDirMounted") + public boolean isRunningInDockerWithConfig() { + Path dockerEnv = Paths.get("/.dockerenv"); + // default to true if not docker + if (!Files.exists(dockerEnv)) { + return true; + } + Path mountInfo = Paths.get("/proc/1/mountinfo"); + // this should always exist, if not some unknown usecase + if (!Files.exists(mountInfo)) { + return true; + } + try { + return Files.lines(mountInfo).anyMatch(line -> line.contains(" /configs ")); + } catch (IOException e) { + return false; + } + } + + @ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration") + @Bean(name = "activeSecurity") + public boolean missingActiveSecurity() { + return false; + } + + @Bean(name = "directoryFilter") + public Predicate processOnlyFiles() { + return path -> { + if (Files.isDirectory(path)) { + return !path.toString().contains("processing"); + } else { + return true; + } + }; + } + + @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(); + } + + @Bean(name = "analyticsPrompt") + @Scope("request") + public boolean analyticsPrompt() { + return applicationProperties.getSystem().getEnableAnalytics() == null; + } + + @Bean(name = "analyticsEnabled") + @Scope("request") + public boolean analyticsEnabled() { + if (applicationProperties.getPremium().isEnabled()) return true; + return applicationProperties.getSystem().isAnalyticsEnabled(); + } + + @Bean(name = "StirlingPDFLabel") + public String stirlingPDFLabel() { + return "Stirling-PDF" + " v" + appVersion(); + } + + @Bean(name = "UUID") + public String uuid() { + return applicationProperties.getAutomaticallyGenerated().getUUID(); + } +}