redact stuff, login page, lang and remember me
This commit is contained in:
parent
cd0e1a3962
commit
41bd801e0d
12 changed files with 324 additions and 209 deletions
|
@ -24,7 +24,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
public class CleanUrlInterceptor implements HandlerInterceptor {
|
public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints", "logout", "error");
|
private static final List<String> ALLOWED_PARAMS = Arrays.asList("lang", "endpoint", "endpoints", "logout", "error", "file");
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,11 +40,9 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
|
||||||
String[] queryParameters = queryString.split("&");
|
String[] queryParameters = queryString.split("&");
|
||||||
for (String param : queryParameters) {
|
for (String param : queryParameters) {
|
||||||
String[] keyValue = param.split("=");
|
String[] keyValue = param.split("=");
|
||||||
System.out.print("astirli " + keyValue[0]);
|
|
||||||
if (keyValue.length != 2) {
|
if (keyValue.length != 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
System.out.print("astirli2 " + keyValue[0]);
|
|
||||||
|
|
||||||
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
if (ALLOWED_PARAMS.contains(keyValue[0])) {
|
||||||
parameters.put(keyValue[0], keyValue[1]);
|
parameters.put(keyValue[0], keyValue[1]);
|
||||||
|
|
|
@ -15,7 +15,11 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.repository.JPATokenRepositoryImpl;
|
||||||
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
|
@ -43,7 +47,7 @@ public class SecurityConfiguration {
|
||||||
|
|
||||||
if(loginEnabledValue) {
|
if(loginEnabledValue) {
|
||||||
|
|
||||||
http.csrf().disable();
|
http.csrf(csrf -> csrf.disable());
|
||||||
http
|
http
|
||||||
.formLogin(formLogin -> formLogin
|
.formLogin(formLogin -> formLogin
|
||||||
.loginPage("/login")
|
.loginPage("/login")
|
||||||
|
@ -55,7 +59,11 @@ public class SecurityConfiguration {
|
||||||
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||||
.logoutSuccessUrl("/login?logout=true")
|
.logoutSuccessUrl("/login?logout=true")
|
||||||
.invalidateHttpSession(true) // Invalidate session
|
.invalidateHttpSession(true) // Invalidate session
|
||||||
.deleteCookies("JSESSIONID")
|
.deleteCookies("JSESSIONID", "remember-me")
|
||||||
|
).rememberMe(rememberMeConfigurer -> rememberMeConfigurer // Use the configurator directly
|
||||||
|
.key("uniqueAndSecret")
|
||||||
|
.tokenRepository(persistentTokenRepository())
|
||||||
|
.tokenValiditySeconds(1209600) // 2 weeks
|
||||||
)
|
)
|
||||||
.authorizeHttpRequests(authz -> authz
|
.authorizeHttpRequests(authz -> authz
|
||||||
.requestMatchers(req -> req.getRequestURI().startsWith("/login") || req.getRequestURI().endsWith(".svg") || req.getRequestURI().startsWith("/register") || req.getRequestURI().startsWith("/error") || req.getRequestURI().startsWith("/images/") || req.getRequestURI().startsWith("/public/") || req.getRequestURI().startsWith("/css/") || req.getRequestURI().startsWith("/js/"))
|
.requestMatchers(req -> req.getRequestURI().startsWith("/login") || req.getRequestURI().endsWith(".svg") || req.getRequestURI().startsWith("/register") || req.getRequestURI().startsWith("/error") || req.getRequestURI().startsWith("/images/") || req.getRequestURI().startsWith("/public/") || req.getRequestURI().startsWith("/css/") || req.getRequestURI().startsWith("/js/"))
|
||||||
|
@ -65,8 +73,7 @@ public class SecurityConfiguration {
|
||||||
.userDetailsService(userDetailsService)
|
.userDetailsService(userDetailsService)
|
||||||
.authenticationProvider(authenticationProvider());
|
.authenticationProvider(authenticationProvider());
|
||||||
} else {
|
} else {
|
||||||
http
|
http.csrf(csrf -> csrf.disable())
|
||||||
.csrf().disable()
|
|
||||||
.authorizeHttpRequests(authz -> authz
|
.authorizeHttpRequests(authz -> authz
|
||||||
.anyRequest().permitAll()
|
.anyRequest().permitAll()
|
||||||
);
|
);
|
||||||
|
@ -84,6 +91,11 @@ public class SecurityConfiguration {
|
||||||
return authProvider;
|
return authProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PersistentTokenRepository persistentTokenRepository() {
|
||||||
|
return new JPATokenRepositoryImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package stirling.software.SPDF.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "persistent_logins")
|
||||||
|
public class PersistentLogin {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "series")
|
||||||
|
private String series;
|
||||||
|
|
||||||
|
@Column(name = "username", length = 64, nullable = false)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(name = "token", length = 64, nullable = false)
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
@Column(name = "last_used", nullable = false)
|
||||||
|
private Date lastUsed;
|
||||||
|
|
||||||
|
public String getSeries() {
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeries(String series) {
|
||||||
|
this.series = series;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLastUsed() {
|
||||||
|
return lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUsed(Date lastUsed) {
|
||||||
|
this.lastUsed = lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Getters, setters, etc.
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
|
||||||
|
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||||
|
import stirling.software.SPDF.model.PersistentLogin;
|
||||||
|
import stirling.software.SPDF.repository.PersistentLoginRepository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class JPATokenRepositoryImpl implements PersistentTokenRepository {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PersistentLoginRepository persistentLoginRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createNewToken(PersistentRememberMeToken token) {
|
||||||
|
PersistentLogin newToken = new PersistentLogin();
|
||||||
|
newToken.setSeries(token.getSeries());
|
||||||
|
newToken.setUsername(token.getUsername());
|
||||||
|
newToken.setToken(token.getTokenValue());
|
||||||
|
newToken.setLastUsed(token.getDate());
|
||||||
|
persistentLoginRepository.save(newToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateToken(String series, String tokenValue, Date lastUsed) {
|
||||||
|
PersistentLogin existingToken = persistentLoginRepository.findById(series).orElse(null);
|
||||||
|
if (existingToken != null) {
|
||||||
|
existingToken.setToken(tokenValue);
|
||||||
|
existingToken.setLastUsed(lastUsed);
|
||||||
|
persistentLoginRepository.save(existingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistentRememberMeToken getTokenForSeries(String seriesId) {
|
||||||
|
PersistentLogin token = persistentLoginRepository.findById(seriesId).orElse(null);
|
||||||
|
if (token != null) {
|
||||||
|
return new PersistentRememberMeToken(token.getUsername(), token.getSeries(), token.getToken(), token.getLastUsed());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUserTokens(String username) {
|
||||||
|
for (PersistentLogin token : persistentLoginRepository.findAll()) {
|
||||||
|
if (token.getUsername().equals(username)) {
|
||||||
|
persistentLoginRepository.delete(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package stirling.software.SPDF.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import stirling.software.SPDF.model.PersistentLogin;
|
||||||
|
|
||||||
|
public interface PersistentLoginRepository extends JpaRepository<PersistentLogin, String> {
|
||||||
|
}
|
|
@ -299,6 +299,10 @@ home.showJS.title=Show Javascript
|
||||||
home.showJS.desc=Searches and displays any JS injected into a PDF
|
home.showJS.desc=Searches and displays any JS injected into a PDF
|
||||||
showJS.tags=JS
|
showJS.tags=JS
|
||||||
|
|
||||||
|
home.autoRedact.title=Auto Redact
|
||||||
|
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
|
||||||
|
showJS.tags=Redact,Hide,black out,black,marker,hidden
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# #
|
# #
|
||||||
# WEB PAGES #
|
# WEB PAGES #
|
||||||
|
@ -307,6 +311,14 @@ showJS.tags=JS
|
||||||
#auto-redact
|
#auto-redact
|
||||||
autoRedact.title=Auto Redact
|
autoRedact.title=Auto Redact
|
||||||
autoRedact.header=Auto Redact
|
autoRedact.header=Auto Redact
|
||||||
|
autoRedact.textsToRedactLabel=Text to Redact (line-separated)
|
||||||
|
autoRedact.textsToRedactPlaceholder=e.g. \nConfidential \nTop-Secret
|
||||||
|
autoRedact.useRegexLabel=Use Regex
|
||||||
|
autoRedact.wholeWordSearchLabel=Whole Word Search
|
||||||
|
autoRedact.customPaddingLabel=Custom Extra Padding
|
||||||
|
autoRedact.convertPDFToImageLabel=Convert PDF to Image
|
||||||
|
autoRedact.submitButton=Submit
|
||||||
|
|
||||||
|
|
||||||
#showJS
|
#showJS
|
||||||
showJS.title=Show Javascript
|
showJS.title=Show Javascript
|
||||||
|
|
3
src/main/resources/static/images/eraser-fill.svg
Normal file
3
src/main/resources/static/images/eraser-fill.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eraser-fill" viewBox="0 0 16 16">
|
||||||
|
<path d="M8.086 2.207a2 2 0 0 1 2.828 0l3.879 3.879a2 2 0 0 1 0 2.828l-5.5 5.5A2 2 0 0 1 7.879 15H5.12a2 2 0 0 1-1.414-.586l-2.5-2.5a2 2 0 0 1 0-2.828l6.879-6.879zm.66 11.34L3.453 8.254 1.914 9.793a1 1 0 0 0 0 1.414l2.5 2.5a1 1 0 0 0 .707.293H7.88a1 1 0 0 0 .707-.293l.16-.16z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 418 B |
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<svg xmsns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 20 20">
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 20 20">
|
||||||
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.539c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.312.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a13.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.694.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.418.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
|
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.539c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.312.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a13.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.694.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.418.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="eu_ES">
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="eu_ES">
|
||||||
<img src="images/flags/eu.svg" alt="icon" width="20" height="15"> Euskara
|
<img src="images/flags/eu.svg" alt="icon" width="20" height="15"> Euskara
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="es_ES">
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="es_ES">
|
||||||
<img src="images/flags/es.svg" alt="icon" width="20" height="15"> Español
|
<img src="images/flags/es.svg" alt="icon" width="20" height="15"> Español
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fr_FR">
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fr_FR">
|
||||||
|
@ -49,8 +49,8 @@
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL">
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL">
|
||||||
<img src="images/flags/nl.svg" alt="icon" width="20" height="15"> Nederlands
|
<img src="images/flags/nl.svg" alt="icon" width="20" height="15"> Nederlands
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ps_PL">
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL">
|
||||||
<img src="images/flags/ps.svg" alt="icon" width="20" height="15"> Polski
|
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_BR">
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_BR">
|
||||||
<img src="images/flags/pt_br.svg" alt="icon" width="20" height="15"> Português (BR)
|
<img src="images/flags/pt_br.svg" alt="icon" width="20" height="15"> Português (BR)
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-watermark', 'images/droplet.svg', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags')}"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-watermark', 'images/droplet.svg', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags')}"></div>
|
||||||
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'images/award.svg', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags')}"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'images/award.svg', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags')}"></div>
|
||||||
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('sanitize-pdf', 'images/sanitize.svg', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags')}"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('sanitize-pdf', 'images/sanitize.svg', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags')}"></div>
|
||||||
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-redact', 'images/eraser-fill.svg', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags')}"></div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav ms-auto flex-nowrap">
|
<ul class="navbar-nav flex-nowrap">
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<img class="navbar-icon" src="images/star.svg" alt="icon" width="24" height="24">
|
<img class="navbar-icon" src="images/star.svg" alt="icon" width="24" height="24">
|
||||||
|
@ -147,75 +147,7 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item">
|
<th:block th:insert="~{fragments/langAndDarkMode :: langAndDarkMode}"></th:block>
|
||||||
<a class="nav-link" id="dark-mode-toggle" href="#">
|
|
||||||
<img class="navbar-icon" id="dark-mode-icon" src="moon.svg" alt="icon" />
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2" viewBox="0 0 20 20">
|
|
||||||
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.539c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.312.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a13.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.694.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.418.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="languageDropdown">
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ar_AR">
|
|
||||||
<img src="images/flags/sa.svg" alt="icon" width="20" height="15"> العربية
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ca_CA">
|
|
||||||
<img src="images/flags/es-ct.svg" alt="icon" width="20" height="15"> Català
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="zh_CN">
|
|
||||||
<img src="images/flags/cn.svg" alt="icon" width="20" height="15"> 简体中文
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="de_DE">
|
|
||||||
<img src="images/flags/de.svg" alt="icon" width="20" height="15"> Deutsch
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_GB">
|
|
||||||
<img src="images/flags/gb.svg" alt="icon" width="20" height="15"> English (GB)
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="en_US">
|
|
||||||
<img src="images/flags/us.svg" alt="icon" width="20" height="15"> English (US)
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="eu_ES">
|
|
||||||
<img src="images/flags/eu.svg" alt="icon" width="20" height="15"> Euskara
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="es_ES">
|
|
||||||
<img src="images/flags/es.svg" alt="icon" width="20" height="15"> Español
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="fr_FR">
|
|
||||||
<img src="images/flags/fr.svg" alt="icon" width="20" height="15"> Français
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="it_IT">
|
|
||||||
<img src="images/flags/it.svg" alt="icon" width="20" height="15"> Italiano
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="nl_NL">
|
|
||||||
<img src="images/flags/nl.svg" alt="icon" width="20" height="15"> Nederlands
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL">
|
|
||||||
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pt_BR">
|
|
||||||
<img src="images/flags/pt_br.svg" alt="icon" width="20" height="15"> Português (BR)
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ro_RO">
|
|
||||||
<img src="images/flags/ro.svg" alt="icon" width="20" height="15"> Romanian
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="sv_SE">
|
|
||||||
<img src="images/flags/se.svg" alt="icon" width="20" height="15"> Svenska
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ru_RU">
|
|
||||||
<img src="images/flags/ru.svg" alt="icon" width="20" height="15"> Русский
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ko_KR">
|
|
||||||
<img src="images/flags/kr.svg" alt="icon" width="20" height="15"> 한국어
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="ja_JP">
|
|
||||||
<img src="images/flags/jp.svg" alt="icon" width="20" height="15"> 日本語
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
<div th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', svgPath='images/extract.svg')}"></div>
|
<div th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', svgPath='images/extract.svg')}"></div>
|
||||||
<div th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', svgPath='images/single-page.svg')}"></div>
|
<div th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', svgPath='images/single-page.svg')}"></div>
|
||||||
<div th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', svgPath='images/js.svg')}"></div>
|
<div th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', svgPath='images/js.svg')}"></div>
|
||||||
|
<div th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', svgPath='images/eraser-fill.svg')}"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,99 @@
|
||||||
<html xmlns:th="http://www.thymeleaf.org">
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
<!-- Hi if you have been redirected here when using API then you might need to supply a X-API-KEY key in header to authenticate! -->
|
<th:block th:insert="~{fragments/common :: head(title=#{login.title})}"></th:block>
|
||||||
<head>
|
<style>
|
||||||
<title>Login</title>
|
html, body {
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
height: 100%;
|
||||||
</head>
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 40px;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 330px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin .checkbox {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin .form-floating:focus-within {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin input[type="text"] {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-signin input[type="password"] {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
.container-flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
width: 100%; /* Set width to 100% */
|
||||||
|
align-items: center; /* Center its children horizontally */
|
||||||
|
}
|
||||||
|
.footer-bottom {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<body>
|
<body>
|
||||||
|
<div class="container-flex">
|
||||||
|
<main class="form-signin text-center">
|
||||||
|
|
||||||
|
<div th:if="${logoutMessage}" class="alert alert-success"
|
||||||
|
th:text="${logoutMessage}"></div>
|
||||||
|
|
||||||
<div id="page-container">
|
|
||||||
<div id="content-wrap">
|
|
||||||
<div class="container">
|
|
||||||
<div class="row justify-content-center align-items-center" style="height:100vh;">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="login-container card">
|
|
||||||
<div class="card-header text-center">
|
|
||||||
<img src="favicon.svg" alt="Logo" class="img-fluid" style="max-width: 100px;"> <!-- Adjust path and style as needed -->
|
|
||||||
<h4>Stirling-PDF Login</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div th:if="${logoutMessage}" class="alert alert-success" th:text="${logoutMessage}"></div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card-body">
|
|
||||||
<form th:action="@{/login}" method="post">
|
<form th:action="@{/login}" method="post">
|
||||||
<div class="mb-3">
|
<img class="mb-4" src="favicon.svg" alt="" width="144" height="144">
|
||||||
<label for="username">Username:</label>
|
<h1 class="h1 mb-3 fw-normal">Stirling-PDF</h1>
|
||||||
<input type="text" id="username" name="username" class="form-control" required="required" />
|
<h2 class="h5 mb-3 fw-normal">Please sign in</h2>
|
||||||
|
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="text" class="form-control" id="username"
|
||||||
|
placeholder="admin"> <label for="username">Username</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="form-floating">
|
||||||
<label for="password">Password:</label>
|
<input type="password" class="form-control" id="password"
|
||||||
<input type="password" id="password" name="password" class="form-control" required="required" />
|
placeholder="Password"> <label for="password">Password</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3 text-center">
|
|
||||||
<input type="submit" value="Login" class="btn btn-primary" />
|
<div class="checkbox mb-3">
|
||||||
|
<label> <input type="checkbox" value="remember-me">
|
||||||
|
Remember me
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign
|
||||||
|
in</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<div class="text-danger text-center">
|
||||||
<div class="card-footer text-danger text-center">
|
<div th:if="${error == 'badcredentials'}">Invalid username or
|
||||||
<div th:if="${error == 'badcredentials'}">
|
password.</div>
|
||||||
Invalid username or password.
|
<div th:if="${error == 'locked'}">Your account has been locked.
|
||||||
</div>
|
|
||||||
<div th:if="${error == 'locked'}">
|
|
||||||
Your account has been locked.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
<th:block th:insert="~{fragments/common :: head(title=#{autoRedact.title})}"></th:block>
|
<th:block th:insert="~{fragments/common :: head(title=#{autoRedact.title})}"></th:block>
|
||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="page-container">
|
<div id="page-container">
|
||||||
<div id="content-wrap">
|
<div id="content-wrap">
|
||||||
|
@ -13,38 +11,37 @@
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2 th:text="#{autoRedact.header}"></h2>
|
<h2 th:text="#{autoRedact.header}"></h2>
|
||||||
|
|
||||||
<form action="/auto-redact" method="post" enctype="multipart/form-data">
|
<form action="/auto-redact" method="post" enctype="multipart/form-data">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
|
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="listOfText" class="form-label">Texts to Redact (line-separated)</label>
|
<label for="listOfText" class="form-label" th:text="#{autoRedact.textsToRedactLabel}"></label>
|
||||||
<textarea class="form-control" id="listOfText" name="listOfText" rows="4" required placeholder="e.g. Confidential,Top-Secret"></textarea>
|
<textarea class="form-control" id="listOfText" name="listOfText" rows="4" required th:placeholder="#{autoRedact.textsToRedactPlaceholder}"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
<div class="mb-3 form-check">
|
||||||
<input type="checkbox" class="form-check-input" id="useRegex" name="useRegex">
|
<input type="checkbox" class="form-check-input" id="useRegex" name="useRegex">
|
||||||
<label class="form-check-label" for="useRegex">Use Regex</label>
|
<label class="form-check-label" for="useRegex" th:text="#{autoRedact.useRegexLabel}"></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
<div class="mb-3 form-check">
|
||||||
<input type="checkbox" class="form-check-input" id="wholeWordSearch" name="wholeWordSearch">
|
<input type="checkbox" class="form-check-input" id="wholeWordSearch" name="wholeWordSearch">
|
||||||
<label class="form-check-label" for="wholeWordSearch">Whole Word Search</label>
|
<label class="form-check-label" for="wholeWordSearch" th:text="#{autoRedact.wholeWordSearchLabel}"></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="customPadding" class="form-label">Custom Padding</label>
|
<label for="customPadding" class="form-label" th:text="#{autoRedact.customPaddingLabel}"></label>
|
||||||
<input type="number" step="0.1" class="form-control" id="customPadding" name="customPadding" placeholder="0.0" value="0.1">
|
<input type="number" step="0.1" class="form-control" id="customPadding" name="customPadding" value="0.1">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
<div class="mb-3 form-check">
|
||||||
<input type="checkbox" class="form-check-input" id="convertPDFToImage" name="convertPDFToImage" checked>
|
<input type="checkbox" class="form-check-input" id="convertPDFToImage" name="convertPDFToImage" checked>
|
||||||
<label class="form-check-label" for="convertPDFToImage">Convert PDF to Image</label>
|
<label class="form-check-label" for="convertPDFToImage" th:text="#{autoRedact.convertPDFToImageLabel}"></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary" th:text="#{autoRedact.submitButton}"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue