mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-23 16:05:09 +00:00
multi module build running
This commit is contained in:
parent
ea04596e35
commit
a328ea9d25
@ -31,6 +31,7 @@ import stirling.software.common.configuration.AppConfig;
|
|||||||
import stirling.software.common.model.ApplicationProperties;
|
import stirling.software.common.model.ApplicationProperties;
|
||||||
import stirling.software.proprietary.security.CustomAuthenticationFailureHandler;
|
import stirling.software.proprietary.security.CustomAuthenticationFailureHandler;
|
||||||
import stirling.software.proprietary.security.CustomAuthenticationSuccessHandler;
|
import stirling.software.proprietary.security.CustomAuthenticationSuccessHandler;
|
||||||
|
import stirling.software.proprietary.security.CustomLogoutSuccessHandler;
|
||||||
import stirling.software.proprietary.security.database.repository.JPATokenRepositoryImpl;
|
import stirling.software.proprietary.security.database.repository.JPATokenRepositoryImpl;
|
||||||
import stirling.software.proprietary.security.database.repository.PersistentLoginRepository;
|
import stirling.software.proprietary.security.database.repository.PersistentLoginRepository;
|
||||||
import stirling.software.proprietary.security.filter.FirstLoginFilter;
|
import stirling.software.proprietary.security.filter.FirstLoginFilter;
|
||||||
@ -168,7 +169,7 @@ public class SecurityConfiguration {
|
|||||||
logout ->
|
logout ->
|
||||||
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||||
.logoutSuccessHandler(
|
.logoutSuccessHandler(
|
||||||
new stirling.software.proprietary.security.CustomLogoutSuccessHandler(applicationProperties, appConfig))
|
new CustomLogoutSuccessHandler(applicationProperties, appConfig))
|
||||||
.clearAuthentication(true)
|
.clearAuthentication(true)
|
||||||
.invalidateHttpSession(true)
|
.invalidateHttpSession(true)
|
||||||
.deleteCookies("JSESSIONID", "remember-me"));
|
.deleteCookies("JSESSIONID", "remember-me"));
|
||||||
@ -293,7 +294,7 @@ public class SecurityConfiguration {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug("SAML 2 login is not enabled. Using default.");
|
log.debug("Login is not enabled.");
|
||||||
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||||
}
|
}
|
||||||
return http.build();
|
return http.build();
|
||||||
|
@ -1,317 +0,0 @@
|
|||||||
package stirling.software.SPDF.config.security;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.DependsOn;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.security.authentication.ProviderManager;
|
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
|
|
||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
|
||||||
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
|
||||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
|
||||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
|
||||||
import org.springframework.security.web.savedrequest.NullRequestCache;
|
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler;
|
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler;
|
|
||||||
import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService;
|
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationFailureHandler;
|
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticationSuccessHandler;
|
|
||||||
import stirling.software.SPDF.config.security.saml2.CustomSaml2ResponseAuthenticationConverter;
|
|
||||||
import stirling.software.SPDF.config.security.session.SessionPersistentRegistry;
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
|
||||||
import stirling.software.SPDF.model.User;
|
|
||||||
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
|
||||||
import stirling.software.SPDF.repository.PersistentLoginRepository;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
@EnableMethodSecurity
|
|
||||||
@Slf4j
|
|
||||||
@DependsOn("runningProOrHigher")
|
|
||||||
public class SecurityConfiguration {
|
|
||||||
|
|
||||||
private final CustomUserDetailsService userDetailsService;
|
|
||||||
private final UserService userService;
|
|
||||||
private final boolean loginEnabledValue;
|
|
||||||
private final boolean runningProOrHigher;
|
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
|
||||||
private final UserAuthenticationFilter userAuthenticationFilter;
|
|
||||||
private final LoginAttemptService loginAttemptService;
|
|
||||||
private final FirstLoginFilter firstLoginFilter;
|
|
||||||
private final SessionPersistentRegistry sessionRegistry;
|
|
||||||
private final PersistentLoginRepository persistentLoginRepository;
|
|
||||||
private final GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper;
|
|
||||||
private final RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations;
|
|
||||||
private final OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver;
|
|
||||||
|
|
||||||
public SecurityConfiguration(
|
|
||||||
PersistentLoginRepository persistentLoginRepository,
|
|
||||||
CustomUserDetailsService userDetailsService,
|
|
||||||
@Lazy UserService userService,
|
|
||||||
@Qualifier("loginEnabled") boolean loginEnabledValue,
|
|
||||||
@Qualifier("runningProOrHigher") boolean runningProOrHigher,
|
|
||||||
ApplicationProperties applicationProperties,
|
|
||||||
UserAuthenticationFilter userAuthenticationFilter,
|
|
||||||
LoginAttemptService loginAttemptService,
|
|
||||||
FirstLoginFilter firstLoginFilter,
|
|
||||||
SessionPersistentRegistry sessionRegistry,
|
|
||||||
@Autowired(required = false) GrantedAuthoritiesMapper oAuth2userAuthoritiesMapper,
|
|
||||||
@Autowired(required = false)
|
|
||||||
RelyingPartyRegistrationRepository saml2RelyingPartyRegistrations,
|
|
||||||
@Autowired(required = false)
|
|
||||||
OpenSaml4AuthenticationRequestResolver saml2AuthenticationRequestResolver) {
|
|
||||||
this.userDetailsService = userDetailsService;
|
|
||||||
this.userService = userService;
|
|
||||||
this.loginEnabledValue = loginEnabledValue;
|
|
||||||
this.runningProOrHigher = runningProOrHigher;
|
|
||||||
this.applicationProperties = applicationProperties;
|
|
||||||
this.userAuthenticationFilter = userAuthenticationFilter;
|
|
||||||
this.loginAttemptService = loginAttemptService;
|
|
||||||
this.firstLoginFilter = firstLoginFilter;
|
|
||||||
this.sessionRegistry = sessionRegistry;
|
|
||||||
this.persistentLoginRepository = persistentLoginRepository;
|
|
||||||
this.oAuth2userAuthoritiesMapper = oAuth2userAuthoritiesMapper;
|
|
||||||
this.saml2RelyingPartyRegistrations = saml2RelyingPartyRegistrations;
|
|
||||||
this.saml2AuthenticationRequestResolver = saml2AuthenticationRequestResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder() {
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
||||||
if (applicationProperties.getSecurity().getCsrfDisabled() || !loginEnabledValue) {
|
|
||||||
http.csrf(csrf -> csrf.disable());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loginEnabledValue) {
|
|
||||||
http.addFilterBefore(
|
|
||||||
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
|
||||||
if (!applicationProperties.getSecurity().getCsrfDisabled()) {
|
|
||||||
CookieCsrfTokenRepository cookieRepo =
|
|
||||||
CookieCsrfTokenRepository.withHttpOnlyFalse();
|
|
||||||
CsrfTokenRequestAttributeHandler requestHandler =
|
|
||||||
new CsrfTokenRequestAttributeHandler();
|
|
||||||
requestHandler.setCsrfRequestAttributeName(null);
|
|
||||||
http.csrf(
|
|
||||||
csrf ->
|
|
||||||
csrf.ignoringRequestMatchers(
|
|
||||||
request -> {
|
|
||||||
String apiKey = request.getHeader("X-API-KEY");
|
|
||||||
// If there's no API key, don't ignore CSRF
|
|
||||||
// (return false)
|
|
||||||
if (apiKey == null || apiKey.trim().isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Validate API key using existing UserService
|
|
||||||
try {
|
|
||||||
Optional<User> user =
|
|
||||||
userService.getUserByApiKey(apiKey);
|
|
||||||
// If API key is valid, ignore CSRF (return
|
|
||||||
// true)
|
|
||||||
// If API key is invalid, don't ignore CSRF
|
|
||||||
// (return false)
|
|
||||||
return user.isPresent();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// If there's any error validating the API
|
|
||||||
// key, don't ignore CSRF
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.csrfTokenRepository(cookieRepo)
|
|
||||||
.csrfTokenRequestHandler(requestHandler));
|
|
||||||
}
|
|
||||||
http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class);
|
|
||||||
http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class);
|
|
||||||
http.sessionManagement(
|
|
||||||
sessionManagement ->
|
|
||||||
sessionManagement
|
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
|
|
||||||
.maximumSessions(10)
|
|
||||||
.maxSessionsPreventsLogin(false)
|
|
||||||
.sessionRegistry(sessionRegistry)
|
|
||||||
.expiredUrl("/login?logout=true"));
|
|
||||||
http.authenticationProvider(daoAuthenticationProvider());
|
|
||||||
http.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()));
|
|
||||||
http.logout(
|
|
||||||
logout ->
|
|
||||||
logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
|
||||||
.logoutSuccessHandler(
|
|
||||||
new CustomLogoutSuccessHandler(applicationProperties))
|
|
||||||
.clearAuthentication(true)
|
|
||||||
.invalidateHttpSession(true)
|
|
||||||
.deleteCookies("JSESSIONID", "remember-me"));
|
|
||||||
http.rememberMe(
|
|
||||||
rememberMeConfigurer -> // Use the configurator directly
|
|
||||||
rememberMeConfigurer
|
|
||||||
.tokenRepository(persistentTokenRepository())
|
|
||||||
.tokenValiditySeconds( // 14 days
|
|
||||||
14 * 24 * 60 * 60)
|
|
||||||
.userDetailsService( // Your existing UserDetailsService
|
|
||||||
userDetailsService)
|
|
||||||
.useSecureCookie( // Enable secure cookie
|
|
||||||
true)
|
|
||||||
.rememberMeParameter( // Form parameter name
|
|
||||||
"remember-me")
|
|
||||||
.rememberMeCookieName( // Cookie name
|
|
||||||
"remember-me")
|
|
||||||
.alwaysRemember(false));
|
|
||||||
http.authorizeHttpRequests(
|
|
||||||
authz ->
|
|
||||||
authz.requestMatchers(
|
|
||||||
req -> {
|
|
||||||
String uri = req.getRequestURI();
|
|
||||||
String contextPath = req.getContextPath();
|
|
||||||
// Remove the context path from the URI
|
|
||||||
String trimmedUri =
|
|
||||||
uri.startsWith(contextPath)
|
|
||||||
? uri.substring(
|
|
||||||
contextPath.length())
|
|
||||||
: uri;
|
|
||||||
return trimmedUri.startsWith("/login")
|
|
||||||
|| trimmedUri.startsWith("/oauth")
|
|
||||||
|| trimmedUri.startsWith("/saml2")
|
|
||||||
|| trimmedUri.endsWith(".svg")
|
|
||||||
|| trimmedUri.startsWith("/register")
|
|
||||||
|| trimmedUri.startsWith("/error")
|
|
||||||
|| trimmedUri.startsWith("/images/")
|
|
||||||
|| trimmedUri.startsWith("/public/")
|
|
||||||
|| trimmedUri.startsWith("/css/")
|
|
||||||
|| trimmedUri.startsWith("/fonts/")
|
|
||||||
|| trimmedUri.startsWith("/js/")
|
|
||||||
|| trimmedUri.startsWith(
|
|
||||||
"/api/v1/info/status");
|
|
||||||
})
|
|
||||||
.permitAll()
|
|
||||||
.anyRequest()
|
|
||||||
.authenticated());
|
|
||||||
// Handle User/Password Logins
|
|
||||||
if (applicationProperties.getSecurity().isUserPass()) {
|
|
||||||
http.formLogin(
|
|
||||||
formLogin ->
|
|
||||||
formLogin
|
|
||||||
.loginPage("/login")
|
|
||||||
.successHandler(
|
|
||||||
new CustomAuthenticationSuccessHandler(
|
|
||||||
loginAttemptService, userService))
|
|
||||||
.failureHandler(
|
|
||||||
new CustomAuthenticationFailureHandler(
|
|
||||||
loginAttemptService, userService))
|
|
||||||
.defaultSuccessUrl("/")
|
|
||||||
.permitAll());
|
|
||||||
}
|
|
||||||
// Handle OAUTH2 Logins
|
|
||||||
if (applicationProperties.getSecurity().isOauth2Active()) {
|
|
||||||
http.oauth2Login(
|
|
||||||
oauth2 ->
|
|
||||||
oauth2.loginPage("/oauth2")
|
|
||||||
.
|
|
||||||
/*
|
|
||||||
This Custom handler is used to check if the OAUTH2 user trying to log in, already exists in the database.
|
|
||||||
If user exists, login proceeds as usual. If user does not exist, then it is auto-created but only if 'OAUTH2AutoCreateUser'
|
|
||||||
is set as true, else login fails with an error message advising the same.
|
|
||||||
*/
|
|
||||||
successHandler(
|
|
||||||
new CustomOAuth2AuthenticationSuccessHandler(
|
|
||||||
loginAttemptService,
|
|
||||||
applicationProperties,
|
|
||||||
userService))
|
|
||||||
.failureHandler(
|
|
||||||
new CustomOAuth2AuthenticationFailureHandler())
|
|
||||||
. // Add existing Authorities from the database
|
|
||||||
userInfoEndpoint(
|
|
||||||
userInfoEndpoint ->
|
|
||||||
userInfoEndpoint
|
|
||||||
.oidcUserService(
|
|
||||||
new CustomOAuth2UserService(
|
|
||||||
applicationProperties,
|
|
||||||
userService,
|
|
||||||
loginAttemptService))
|
|
||||||
.userAuthoritiesMapper(
|
|
||||||
oAuth2userAuthoritiesMapper))
|
|
||||||
.permitAll());
|
|
||||||
}
|
|
||||||
// Handle SAML
|
|
||||||
if (applicationProperties.getSecurity().isSaml2Active() && runningProOrHigher) {
|
|
||||||
// Configure the authentication provider
|
|
||||||
OpenSaml4AuthenticationProvider authenticationProvider =
|
|
||||||
new OpenSaml4AuthenticationProvider();
|
|
||||||
authenticationProvider.setResponseAuthenticationConverter(
|
|
||||||
new CustomSaml2ResponseAuthenticationConverter(userService));
|
|
||||||
http.authenticationProvider(authenticationProvider)
|
|
||||||
.saml2Login(
|
|
||||||
saml2 -> {
|
|
||||||
try {
|
|
||||||
saml2.loginPage("/saml2")
|
|
||||||
.relyingPartyRegistrationRepository(
|
|
||||||
saml2RelyingPartyRegistrations)
|
|
||||||
.authenticationManager(
|
|
||||||
new ProviderManager(authenticationProvider))
|
|
||||||
.successHandler(
|
|
||||||
new CustomSaml2AuthenticationSuccessHandler(
|
|
||||||
loginAttemptService,
|
|
||||||
applicationProperties,
|
|
||||||
userService))
|
|
||||||
.failureHandler(
|
|
||||||
new CustomSaml2AuthenticationFailureHandler())
|
|
||||||
.authenticationRequestResolver(
|
|
||||||
saml2AuthenticationRequestResolver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error configuring SAML 2 login", e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.debug("SAML 2 login is not enabled. Using default.");
|
|
||||||
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
|
||||||
}
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
|
||||||
provider.setUserDetailsService(userDetailsService);
|
|
||||||
provider.setPasswordEncoder(passwordEncoder());
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public IPRateLimitingFilter rateLimitingFilter() {
|
|
||||||
// Example limit TODO add config level
|
|
||||||
int maxRequestsPerIp = 1000000;
|
|
||||||
return new IPRateLimitingFilter(maxRequestsPerIp, maxRequestsPerIp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public PersistentTokenRepository persistentTokenRepository() {
|
|
||||||
return new JPATokenRepositoryImpl(persistentLoginRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public boolean activeSecurity() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.common.model.api.PDFFile;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = false)
|
|
||||||
public class SplitPdfByChaptersRequest extends PDFFile {
|
|
||||||
@Schema(
|
|
||||||
description = "Whether to include Metadata or not",
|
|
||||||
defaultValue = "true",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean includeMetadata;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Whether to allow duplicates or not",
|
|
||||||
defaultValue = "true",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean allowDuplicates;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Maximum bookmark level required",
|
|
||||||
minimum = "0",
|
|
||||||
defaultValue = "2",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Integer bookmarkLevel;
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.converters;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ConvertToImageRequest extends PDFWithPageNums {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The output image format",
|
|
||||||
defaultValue = "png",
|
|
||||||
allowableValues = {"png", "jpeg", "jpg", "gif", "webp"},
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String imageFormat;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"Choose between a single image containing all pages or separate images for each"
|
|
||||||
+ " page",
|
|
||||||
defaultValue = "multiple",
|
|
||||||
allowableValues = {"single", "multiple"},
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String singleOrMultiple;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The color type of the output image(s)",
|
|
||||||
defaultValue = "color",
|
|
||||||
allowableValues = {"color", "greyscale", "blackwhite"},
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String colorType;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The DPI (dots per inch) for the output image(s)",
|
|
||||||
defaultValue = "300",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Integer dpi;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.filter;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ContainsTextRequest extends PDFWithPageNums {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The text to check for",
|
|
||||||
defaultValue = "text",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String text;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.filter;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFComparison;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class FileSizeRequest extends PDFComparison {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Size of the file in bytes",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED,
|
|
||||||
defaultValue = "0")
|
|
||||||
private long fileSize;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.filter;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFComparison;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class PageRotationRequest extends PDFComparison {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Rotation in degrees",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED,
|
|
||||||
defaultValue = "0")
|
|
||||||
private int rotation;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.filter;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFComparison;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class PageSizeRequest extends PDFComparison {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Standard Page Size",
|
|
||||||
allowableValues = {"A0", "A1", "A2", "A3", "A4", "A5", "A6", "LETTER", "LEGAL"},
|
|
||||||
defaultValue = "A4",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String standardPageSize;
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.general;
|
|
||||||
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class OverlayPdfsRequest extends PDFFile {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"An array of PDF files to be used as overlays on the base PDF. The order in"
|
|
||||||
+ " these files is applied based on the selected mode.",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private MultipartFile[] overlayFiles;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"The mode of overlaying: 'SequentialOverlay' for sequential application,"
|
|
||||||
+ " 'InterleavedOverlay' for round-robin application, 'FixedRepeatOverlay'"
|
|
||||||
+ " for fixed repetition based on provided counts",
|
|
||||||
allowableValues = {"SequentialOverlay", "InterleavedOverlay", "FixedRepeatOverlay"},
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String overlayMode;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"An array of integers specifying the number of times each corresponding overlay"
|
|
||||||
+ " file should be applied in the 'FixedRepeatOverlay' mode. This should"
|
|
||||||
+ " match the length of the overlayFiles array.",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private int[] counts;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Overlay position 0 is Foregound, 1 is Background",
|
|
||||||
allowableValues = {"0", "1"},
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED,
|
|
||||||
type = "number")
|
|
||||||
private int overlayPosition;
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.misc;
|
|
||||||
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class AddStampRequest extends PDFWithPageNums {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The stamp type (text or image)",
|
|
||||||
allowableValues = {"text", "image"},
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String stampType;
|
|
||||||
|
|
||||||
@Schema(description = "The stamp text", defaultValue = "Stirling Software")
|
|
||||||
private String stampText;
|
|
||||||
|
|
||||||
@Schema(description = "The stamp image")
|
|
||||||
private MultipartFile stampImage;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The selected alphabet of the stamp text",
|
|
||||||
allowableValues = {"roman", "arabic", "japanese", "korean", "chinese"},
|
|
||||||
defaultValue = "roman")
|
|
||||||
private String alphabet = "roman";
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The font size of the stamp text and image",
|
|
||||||
defaultValue = "30",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private float fontSize;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The rotation of the stamp in degrees",
|
|
||||||
defaultValue = "0",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private float rotation;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The opacity of the stamp (0.0 - 1.0)",
|
|
||||||
defaultValue = "0.5",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private float opacity;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"Position for stamp placement based on a 1-9 grid (1: bottom-left, 2: bottom-center,"
|
|
||||||
+ " 3: bottom-right, 4: middle-left, 5: middle-center, 6: middle-right,"
|
|
||||||
+ " 7: top-left, 8: top-center, 9: top-right)",
|
|
||||||
allowableValues = {"1", "2", "3", "4", "5", "6", "7", "8", "9"},
|
|
||||||
defaultValue = "5",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private int position;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"Override X coordinate for stamp placement. If set, it will override the"
|
|
||||||
+ " position-based calculation. Negative value means no override.",
|
|
||||||
defaultValue = "-1",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private float overrideX; // Default to -1 indicating no override
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"Override Y coordinate for stamp placement. If set, it will override the"
|
|
||||||
+ " position-based calculation. Negative value means no override.",
|
|
||||||
defaultValue = "-1",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private float overrideY; // Default to -1 indicating no override
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Specifies the margin size for the stamp.",
|
|
||||||
allowableValues = {"small", "medium", "large", "x-large"},
|
|
||||||
defaultValue = "medium",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String customMargin;
|
|
||||||
|
|
||||||
@Schema(description = "The color of the stamp text", defaultValue = "#d3d3d3")
|
|
||||||
private String customColor;
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.misc;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class MetadataRequest extends PDFFile {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Delete all metadata if set to true",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean deleteAll;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The author of the document",
|
|
||||||
defaultValue = "author",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String author;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The creation date of the document (format: yyyy/MM/dd HH:mm:ss)",
|
|
||||||
pattern = "yyyy/MM/dd HH:mm:ss",
|
|
||||||
defaultValue = "2023/10/01 12:00:00",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String creationDate;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The creator of the document",
|
|
||||||
defaultValue = "creator",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String creator;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The keywords for the document",
|
|
||||||
defaultValue = "keywords",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String keywords;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The modification date of the document (format: yyyy/MM/dd HH:mm:ss)",
|
|
||||||
pattern = "yyyy/MM/dd HH:mm:ss",
|
|
||||||
defaultValue = "2023/10/01 12:00:00",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String modificationDate;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The producer of the document",
|
|
||||||
defaultValue = "producer",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String producer;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The subject of the document",
|
|
||||||
defaultValue = "subject",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String subject;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The title of the document",
|
|
||||||
defaultValue = "title",
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String title;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The trapped status of the document",
|
|
||||||
defaultValue = "False",
|
|
||||||
allowableValues = {"True", "False", "Unknown"},
|
|
||||||
requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
|
||||||
private String trapped;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"Map list of key and value of custom parameters. Note these must start with"
|
|
||||||
+ " customKey and customValue if they are non-standard")
|
|
||||||
private Map<String, String> allRequestParams;
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.security;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class AddPasswordRequest extends PDFFile {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"The owner password to be added to the PDF file (Restricts what can be done"
|
|
||||||
+ " with the document once it is opened)",
|
|
||||||
format = "password")
|
|
||||||
private String ownerPassword;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description =
|
|
||||||
"The password to be added to the PDF file (Restricts the opening of the"
|
|
||||||
+ " document itself.)",
|
|
||||||
format = "password")
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The length of the encryption key",
|
|
||||||
allowableValues = {"40", "128", "256"},
|
|
||||||
defaultValue = "256",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private int keyLength = 256;
|
|
||||||
|
|
||||||
@Schema(description = "Whether document assembly is prevented", defaultValue = "false")
|
|
||||||
private Boolean preventAssembly;
|
|
||||||
|
|
||||||
@Schema(description = "Whether content extraction is prevented", defaultValue = "false")
|
|
||||||
private Boolean preventExtractContent;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Whether content extraction for accessibility is prevented",
|
|
||||||
defaultValue = "false")
|
|
||||||
private Boolean preventExtractForAccessibility;
|
|
||||||
|
|
||||||
@Schema(description = "Whether form filling is prevented", defaultValue = "false")
|
|
||||||
private Boolean preventFillInForm;
|
|
||||||
|
|
||||||
@Schema(description = "Whether document modification is prevented", defaultValue = "false")
|
|
||||||
private Boolean preventModify;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Whether modification of annotations is prevented",
|
|
||||||
defaultValue = "false")
|
|
||||||
private Boolean preventModifyAnnotations;
|
|
||||||
|
|
||||||
@Schema(description = "Whether printing of the document is prevented", defaultValue = "false")
|
|
||||||
private Boolean preventPrinting;
|
|
||||||
|
|
||||||
@Schema(description = "Whether faithful printing is prevented", defaultValue = "false")
|
|
||||||
private Boolean preventPrintingFaithful;
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.security;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFWithPageNums;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ManualRedactPdfRequest extends PDFWithPageNums {
|
|
||||||
@Schema(
|
|
||||||
description = "A list of areas that should be redacted",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private List<RedactionArea> redactions;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Convert the redacted PDF to an image",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean convertPDFToImage;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The color used to fully redact certain pages",
|
|
||||||
defaultValue = "#000000",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String pageRedactionColor;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.security;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.common.model.api.PDFFile;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class RedactPdfRequest extends PDFFile {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "List of text to redact from the PDF",
|
|
||||||
defaultValue = "text,text2",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String listOfText;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Whether to use regex for the listOfText",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean useRegex;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Whether to use whole word search",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean wholeWordSearch;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "The color for redaction",
|
|
||||||
defaultValue = "#000000",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String redactColor;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Custom padding for redaction",
|
|
||||||
type = "number",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private float customPadding;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Convert the redacted PDF to an image",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean convertPDFToImage;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package stirling.software.SPDF.model.api.security;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.api.PDFFile;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class SanitizePdfRequest extends PDFFile {
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Remove JavaScript actions from the PDF",
|
|
||||||
defaultValue = "true",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean removeJavaScript;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Remove embedded files from the PDF",
|
|
||||||
defaultValue = "true",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean removeEmbeddedFiles;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Remove XMP metadata from the PDF",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean removeXMPMetadata;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Remove document info metadata from the PDF",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean removeMetadata;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Remove links from the PDF",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean removeLinks;
|
|
||||||
|
|
||||||
@Schema(
|
|
||||||
description = "Remove fonts from the PDF",
|
|
||||||
defaultValue = "false",
|
|
||||||
requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Boolean removeFonts;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
|
||||||
<head>
|
|
||||||
<th:block th:insert="~{fragments/common :: head(title=#{removeBlanks.title}, header=#{removeBlanks.header})}"></th:block>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
|
||||||
<div id="page-container">
|
|
||||||
<div id="content-wrap">
|
|
||||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
|
||||||
<br><br>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-6 bg-card">
|
|
||||||
<div class="tool-header">
|
|
||||||
<span class="material-symbols-rounded tool-header-icon other">scan_delete</span>
|
|
||||||
<span class="tool-header-text" th:text="#{removeBlanks.header}"></span>
|
|
||||||
</div>
|
|
||||||
<form id="multiPdfForm" th:action="@{'/api/v1/misc/remove-blanks'}" method="post" enctype="multipart/form-data">
|
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="threshold" th:text="#{removeBlanks.threshold}"></label>
|
|
||||||
<input type="number" class="form-control" id="threshold" name="threshold" value="10" min="0" max="255" step="1">
|
|
||||||
<small id="thresholdHelp" class="form-text text-muted" th:text="#{removeBlanks.thresholdDesc}"></small>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="whitePercent" th:text="#{removeBlanks.whitePercent}"></label>
|
|
||||||
<input type="number" class="form-control" id="whitePercent" name="whitePercent" value="99.9" step="0.1" min="0.1" max="100">
|
|
||||||
<small id="whitePercentHelp" class="form-text text-muted" th:text="#{removeBlanks.whitePercentDesc}"></small>
|
|
||||||
</div>
|
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeBlanks.submit}"></button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,26 +0,0 @@
|
|||||||
package stirling.software.SPDF.utils;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public class RequestUriUtilsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsStaticResource() {
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/css/styles.css"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/js/script.js"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/images/logo.png"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/public/index.html"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/pdfjs/pdf.worker.js"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/api/v1/info/status"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/some-path/icon.svg"));
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("/api/v1/users"));
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("/api/v1/orders"));
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("/"));
|
|
||||||
assertTrue(RequestUriUtils.isStaticResource("/login"));
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("/register"));
|
|
||||||
assertFalse(RequestUriUtils.isStaticResource("/api/v1/products"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,9 +14,9 @@ server.error.whitelabel.enabled=false
|
|||||||
server.error.include-stacktrace=always
|
server.error.include-stacktrace=always
|
||||||
server.error.include-exception=true
|
server.error.include-exception=true
|
||||||
server.error.include-message=always
|
server.error.include-message=always
|
||||||
logging.level.org.springframework.web=DEBUG
|
#logging.level.org.springframework.web=DEBUG
|
||||||
logging.level.org.springframework=DEBUG
|
#logging.level.org.springframework=DEBUG
|
||||||
logging.level.org.springframework.security=DEBUG
|
#logging.level.org.springframework.security=DEBUG
|
||||||
spring.servlet.multipart.max-file-size=2000MB
|
spring.servlet.multipart.max-file-size=2000MB
|
||||||
spring.servlet.multipart.max-request-size=2000MB
|
spring.servlet.multipart.max-request-size=2000MB
|
||||||
server.servlet.session.tracking-modes=cookie
|
server.servlet.session.tracking-modes=cookie
|
||||||
|
@ -124,7 +124,7 @@ pipelineOptions.validateButton=Validar
|
|||||||
# ENTERPRISE EDITION #
|
# ENTERPRISE EDITION #
|
||||||
########################
|
########################
|
||||||
enterpriseEdition.button=Actualiza a Pro
|
enterpriseEdition.button=Actualiza a Pro
|
||||||
enterpriseEdition.warning=Esta característica está disponible solamente para usuarios Pro.
|
enterpriseEdition.warning=Esta característica está únicamente disponible para usuarios Pro.
|
||||||
enterpriseEdition.yamlAdvert=Stirling PDF Pro soporta configuración de ficheros YAML y otras características SSO.
|
enterpriseEdition.yamlAdvert=Stirling PDF Pro soporta configuración de ficheros YAML y otras características SSO.
|
||||||
enterpriseEdition.ssoAdvert=¿Busca más funciones de administración de usuarios? Consulte Stirling PDF Pro
|
enterpriseEdition.ssoAdvert=¿Busca más funciones de administración de usuarios? Consulte Stirling PDF Pro
|
||||||
|
|
||||||
@ -364,9 +364,9 @@ home.compressPdfs.title=Comprimir
|
|||||||
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del archivo
|
home.compressPdfs.desc=Comprimir PDFs para reducir el tamaño del archivo
|
||||||
compressPdfs.tags=aplastar,pequeño,diminuto
|
compressPdfs.tags=aplastar,pequeño,diminuto
|
||||||
|
|
||||||
home.unlockPDFForms.title=Desbloquear formularios PDF
|
home.unlockPDFForms.title=Unlock PDF Forms
|
||||||
home.unlockPDFForms.desc=Eliminar la propiedad de solo-lectura de los campos de formulario en un documento PDF.
|
home.unlockPDFForms.desc=Remove read-only property of form fields in a PDF document.
|
||||||
unlockPDFForms.tags=quitar,eliminar,formulario,campo,solo-lectura
|
unlockPDFForms.tags=remove,delete,form,field,readonly
|
||||||
|
|
||||||
home.changeMetadata.title=Cambiar metadatos
|
home.changeMetadata.title=Cambiar metadatos
|
||||||
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
home.changeMetadata.desc=Cambiar/Eliminar/Añadir metadatos al documento PDF
|
||||||
@ -609,7 +609,7 @@ login.userIsDisabled=El usuario está desactivado, actualmente el acceso está b
|
|||||||
login.alreadyLoggedIn=Ya ha iniciado sesión en
|
login.alreadyLoggedIn=Ya ha iniciado sesión en
|
||||||
login.alreadyLoggedIn2=dispositivos. Cierre sesión en los dispositivos y vuelva a intentarlo.
|
login.alreadyLoggedIn2=dispositivos. Cierre sesión en los dispositivos y vuelva a intentarlo.
|
||||||
login.toManySessions=Tiene demasiadas sesiones activas
|
login.toManySessions=Tiene demasiadas sesiones activas
|
||||||
login.logoutMessage=Se ha cerrado su sesión.
|
login.logoutMessage=You have been logged out.
|
||||||
|
|
||||||
#auto-redact
|
#auto-redact
|
||||||
autoRedact.title=Auto Censurar Texto
|
autoRedact.title=Auto Censurar Texto
|
||||||
@ -1023,7 +1023,7 @@ multiTool.deleteSelected=Borrar selecionado(s)
|
|||||||
multiTool.downloadAll=Exportar
|
multiTool.downloadAll=Exportar
|
||||||
multiTool.downloadSelected=Exportar selecionado(s)
|
multiTool.downloadSelected=Exportar selecionado(s)
|
||||||
|
|
||||||
multiTool.insertPageBreak=Insertar salto de página
|
multiTool.insertPageBreak=Insertar salto página
|
||||||
multiTool.addFile=Agregar Archivo
|
multiTool.addFile=Agregar Archivo
|
||||||
multiTool.rotateLeft=Rotar a la izquierda
|
multiTool.rotateLeft=Rotar a la izquierda
|
||||||
multiTool.rotateRight=Rotar a la derecha
|
multiTool.rotateRight=Rotar a la derecha
|
||||||
@ -1061,10 +1061,10 @@ pageRemover.placeholder=(por ejemplo 1,2,6 o 1-10,15-30)
|
|||||||
|
|
||||||
|
|
||||||
#rotate
|
#rotate
|
||||||
rotate.title=Girar PDF
|
rotate.title=Rotar PDF
|
||||||
rotate.header=Girar PDF
|
rotate.header=Rotar PDF
|
||||||
rotate.selectAngle=Seleccionar ángulo de giro (en múltiplos de 90 grados):
|
rotate.selectAngle=Seleccionar ángulo de rotación (en múltiplos de 90 grados):
|
||||||
rotate.submit=Girar
|
rotate.submit=Rotar
|
||||||
|
|
||||||
|
|
||||||
#split-pdfs
|
#split-pdfs
|
||||||
@ -1197,9 +1197,9 @@ changeMetadata.selectText.5=Agregar entrada de metadatos personalizados
|
|||||||
changeMetadata.submit=Cambiar
|
changeMetadata.submit=Cambiar
|
||||||
|
|
||||||
#unlockPDFForms
|
#unlockPDFForms
|
||||||
unlockPDFForms.title=Eliminar solo-lectura de los campos de formulario
|
unlockPDFForms.title=Remove Read-Only from Form Fields
|
||||||
unlockPDFForms.header=Desbloquear los formularios PDF
|
unlockPDFForms.header=Unlock PDF Forms
|
||||||
unlockPDFForms.submit=Eliminar
|
unlockPDFForms.submit=Remove
|
||||||
|
|
||||||
#pdfToPDFA
|
#pdfToPDFA
|
||||||
pdfToPDFA.title=PDF a PDF/A
|
pdfToPDFA.title=PDF a PDF/A
|
||||||
|
@ -364,9 +364,9 @@ home.compressPdfs.title=壓縮
|
|||||||
home.compressPdfs.desc=壓縮 PDF 以減少其檔案大小。
|
home.compressPdfs.desc=壓縮 PDF 以減少其檔案大小。
|
||||||
compressPdfs.tags=壓縮,小,微小
|
compressPdfs.tags=壓縮,小,微小
|
||||||
|
|
||||||
home.unlockPDFForms.title=解鎖 PDF 表單
|
home.unlockPDFForms.title=Unlock PDF Forms
|
||||||
home.unlockPDFForms.desc=移除 PDF 文件中表單欄位的唯讀屬性
|
home.unlockPDFForms.desc=Remove read-only property of form fields in a PDF document.
|
||||||
unlockPDFForms.tags=移除,刪除,表格,欄位,唯讀
|
unlockPDFForms.tags=remove,delete,form,field,readonly
|
||||||
|
|
||||||
home.changeMetadata.title=變更中繼資料
|
home.changeMetadata.title=變更中繼資料
|
||||||
home.changeMetadata.desc=從 PDF 檔案中變更/移除/新增中繼資料
|
home.changeMetadata.desc=從 PDF 檔案中變更/移除/新增中繼資料
|
||||||
@ -1197,9 +1197,9 @@ changeMetadata.selectText.5=新增自訂中繼資料項目
|
|||||||
changeMetadata.submit=變更
|
changeMetadata.submit=變更
|
||||||
|
|
||||||
#unlockPDFForms
|
#unlockPDFForms
|
||||||
unlockPDFForms.title=移除表單欄位的唯讀限制
|
unlockPDFForms.title=Remove Read-Only from Form Fields
|
||||||
unlockPDFForms.header=解鎖 PDF 表單
|
unlockPDFForms.header=Unlock PDF Forms
|
||||||
unlockPDFForms.submit=移除
|
unlockPDFForms.submit=Remove
|
||||||
|
|
||||||
#pdfToPDFA
|
#pdfToPDFA
|
||||||
pdfToPDFA.title=PDF 轉 PDF/A
|
pdfToPDFA.title=PDF 轉 PDF/A
|
||||||
|
@ -4,8 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import stirling.software.spdf.model.api.PDFWithPageNums;
|
||||||
import stirling.software.common.model.api.PDFWithPageNums;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ -11,6 +11,9 @@ import stirling.software.spdf.model.api.PDFWithPageNums;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class ContainsTextRequest extends PDFWithPageNums {
|
public class ContainsTextRequest extends PDFWithPageNums {
|
||||||
|
|
||||||
@Schema(description = "The text to check for", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(
|
||||||
|
description = "The text to check for",
|
||||||
|
defaultValue = "text",
|
||||||
|
requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String text;
|
private String text;
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ server.error.whitelabel.enabled=false
|
|||||||
server.error.include-stacktrace=always
|
server.error.include-stacktrace=always
|
||||||
server.error.include-exception=true
|
server.error.include-exception=true
|
||||||
server.error.include-message=always
|
server.error.include-message=always
|
||||||
logging.level.org.springframework.web=DEBUG
|
#logging.level.org.springframework.web=DEBUG
|
||||||
logging.level.org.springframework=DEBUG
|
#logging.level.org.springframework=DEBUG
|
||||||
logging.level.org.springframework.security=DEBUG
|
#logging.level.org.springframework.security=DEBUG
|
||||||
spring.servlet.multipart.max-file-size=2000MB
|
spring.servlet.multipart.max-file-size=2000MB
|
||||||
spring.servlet.multipart.max-request-size=2000MB
|
spring.servlet.multipart.max-request-size=2000MB
|
||||||
server.servlet.session.tracking-modes=cookie
|
server.servlet.session.tracking-modes=cookie
|
||||||
|
@ -21,12 +21,12 @@
|
|||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="threshold" th:text="#{removeBlanks.threshold}"></label>
|
<label for="threshold" th:text="#{removeBlanks.threshold}"></label>
|
||||||
<input type="number" class="form-control" id="threshold" name="threshold" value="10">
|
<input type="number" class="form-control" id="threshold" name="threshold" value="10" min="0" max="255" step="1">
|
||||||
<small id="thresholdHelp" class="form-text text-muted" th:text="#{removeBlanks.thresholdDesc}"></small>
|
<small id="thresholdHelp" class="form-text text-muted" th:text="#{removeBlanks.thresholdDesc}"></small>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="whitePercent" th:text="#{removeBlanks.whitePercent}"></label>
|
<label for="whitePercent" th:text="#{removeBlanks.whitePercent}"></label>
|
||||||
<input type="number" class="form-control" id="whitePercent" name="whitePercent" value="99.9" step="0.1">
|
<input type="number" class="form-control" id="whitePercent" name="whitePercent" value="99.9" step="0.1" min="0.1" max="100">
|
||||||
<small id="whitePercentHelp" class="form-text text-muted" th:text="#{removeBlanks.whitePercentDesc}"></small>
|
<small id="whitePercentHelp" class="form-text text-muted" th:text="#{removeBlanks.whitePercentDesc}"></small>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeBlanks.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{removeBlanks.submit}"></button>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user