diff --git a/pom.xml b/pom.xml
index 6a66732c..484be4eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,8 @@
1.8
+ 1.19.0
+ 4.10.0
@@ -172,6 +174,57 @@
1.0.0
+
+
+ com.redis.testcontainers
+ testcontainers-redis
+ 1.6.4
+ test
+
+
+ org.zaproxy
+ zap-clientapi
+ 1.12.0
+ test
+
+
+ org.seleniumhq.selenium
+ selenium-java
+ ${selenium.version}
+ test
+
+
+ org.seleniumhq.selenium
+ selenium-firefox-driver
+ ${selenium.version}
+ test
+
+
+ org.asynchttpclient
+ async-http-client
+ 2.12.3
+ test
+
+
+ com.google.guava
+ guava
+ 31.1-jre
+ test
+
+
+ org.testng
+ testng
+ 7.7.1
+ test
+
+
+ io.rest-assured
+ rest-assured
+ 5.3.1
+ test
+
+
+
diff --git a/src/main/java/com/nonononoki/alovoa/component/AuthFilter.java b/src/main/java/com/nonononoki/alovoa/component/AuthFilter.java
index 29d806b6..be5314b6 100644
--- a/src/main/java/com/nonononoki/alovoa/component/AuthFilter.java
+++ b/src/main/java/com/nonononoki/alovoa/component/AuthFilter.java
@@ -3,6 +3,7 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -12,24 +13,37 @@
public class AuthFilter extends UsernamePasswordAuthenticationFilter {
- private static final String USERNAME = "username";
- private static final String PASSWORD = "password";
- private static final String CAPTCHA_ID = "captchaId";
- private static final String CAPTCHA_TEXT = "captchaText";
- public static final String REDIRECT_URL = "redirect-url";
-
- @Override
- public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
- throws AuthenticationException {
-
- String username = request.getParameter(USERNAME);
- String password = request.getParameter(PASSWORD);
- long captchaId = Long.parseLong(request.getParameter(CAPTCHA_ID));
- String captchaText = request.getParameter(CAPTCHA_TEXT);
- request.getSession().setAttribute(REDIRECT_URL, request.getParameter(REDIRECT_URL));
-
- AuthToken auth = new AuthToken(username, password, captchaId, captchaText);
- AuthenticationManager am = this.getAuthenticationManager();
- return am.authenticate(auth);
- }
+ private static final String USERNAME = "username";
+ private static final String PASSWORD = "password";
+ private static final String CAPTCHA_ID = "captchaId";
+ private static final String CAPTCHA_TEXT = "captchaText";
+ public static final String REDIRECT_URL = "redirect-url";
+
+ @Value("${app.captcha.login.enabled}")
+ private String captchaLoginEnabled;
+
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+ throws AuthenticationException {
+ long captchaId;
+ String captchaText;
+
+ String username = request.getParameter(USERNAME);
+ String password = request.getParameter(PASSWORD);
+
+ if (Boolean.parseBoolean(captchaLoginEnabled)) {
+ captchaId = Long.parseLong(request.getParameter(CAPTCHA_ID));
+ captchaText = request.getParameter(CAPTCHA_TEXT);
+ } else {
+ captchaId = -1;
+ captchaText = null;
+ }
+
+ request.getSession().setAttribute(REDIRECT_URL, request.getParameter(REDIRECT_URL));
+
+ AuthToken auth = new AuthToken(username, password, captchaId, captchaText);
+ AuthenticationManager am = this.getAuthenticationManager();
+ return am.authenticate(auth);
+
+ }
}
diff --git a/src/main/java/com/nonononoki/alovoa/component/AuthProvider.java b/src/main/java/com/nonononoki/alovoa/component/AuthProvider.java
index c65019e3..278775aa 100644
--- a/src/main/java/com/nonononoki/alovoa/component/AuthProvider.java
+++ b/src/main/java/com/nonononoki/alovoa/component/AuthProvider.java
@@ -6,6 +6,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
@@ -37,7 +38,10 @@ public class AuthProvider implements AuthenticationProvider {
@Autowired
private PasswordEncoder passwordEncoder;
-
+
+ @Value("${app.captcha.login.enabled}")
+ private String captchaEnabled;
+
@SuppressWarnings("unused")
private static final Logger logger = LoggerFactory.getLogger(AuthProvider.class);
@@ -50,15 +54,20 @@ public Authentication authenticate(Authentication authentication) throws Authent
long captchaId = a.getCaptchaId();
String captchaText = a.getCaptchaText();
- Captcha c = captchaRepo.findById(captchaId).orElse(null);
- if (c == null) {
- throw new BadCredentialsException("");
- }
+ if (Boolean.parseBoolean(captchaEnabled)) {
+ logger.debug("Captcha enabled, so check captcha");
+ Captcha c = captchaRepo.findById(captchaId).orElse(null);
+ if (c == null) {
+ throw new BadCredentialsException("");
+ }
- captchaRepo.delete(c);
+ captchaRepo.delete(c);
- if (!c.getText().equalsIgnoreCase(captchaText)) {
- throw new BadCredentialsException("");
+ if (!c.getText().equalsIgnoreCase(captchaText)) {
+ throw new BadCredentialsException("");
+ }
+ } else {
+ logger.debug("Captcha disabled, so we do not care about it");
}
User user = userRepo.findByEmail(email);
diff --git a/src/main/java/com/nonononoki/alovoa/html/DeleteAccountResource.java b/src/main/java/com/nonononoki/alovoa/html/DeleteAccountResource.java
index 3bce4cb4..fecacb80 100644
--- a/src/main/java/com/nonononoki/alovoa/html/DeleteAccountResource.java
+++ b/src/main/java/com/nonononoki/alovoa/html/DeleteAccountResource.java
@@ -40,6 +40,9 @@ public class DeleteAccountResource {
@Value("${app.user.delete.duration.valid}")
private long accountDeleteDuration;
+ @Value("${app.captcha.delete.enabled}")
+ private String captchaDeleteEnabled;
+
@GetMapping("/delete-account/{tokenString}")
public ModelAndView deleteAccount(@PathVariable String tokenString) throws AlovoaException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException,
@@ -57,6 +60,7 @@ public ModelAndView deleteAccount(@PathVariable String tokenString) throws Alovo
active = true;
}
mav.addObject("active", active);
+ mav.addObject("captchaEnabled", Boolean.valueOf(captchaDeleteEnabled));
return mav;
}
diff --git a/src/main/java/com/nonononoki/alovoa/html/ImprintResource.java b/src/main/java/com/nonononoki/alovoa/html/ImprintResource.java
index 838bc1e7..626da989 100644
--- a/src/main/java/com/nonononoki/alovoa/html/ImprintResource.java
+++ b/src/main/java/com/nonononoki/alovoa/html/ImprintResource.java
@@ -11,11 +11,16 @@ public class ImprintResource {
@Value("${app.company.name}")
private String companyName;
+ @Value("${app.captcha.imprint.enabled}")
+ private String captchaImprintEnabled;
+
@GetMapping("/imprint")
public ModelAndView imprint() {
ModelAndView mav = new ModelAndView("imprint");
mav.addObject("companyName", companyName);
+ mav.addObject("captchaEnabled", Boolean.valueOf(captchaImprintEnabled));
+
return mav;
}
}
diff --git a/src/main/java/com/nonononoki/alovoa/html/LoginResource.java b/src/main/java/com/nonononoki/alovoa/html/LoginResource.java
index d03af09c..e0887693 100644
--- a/src/main/java/com/nonononoki/alovoa/html/LoginResource.java
+++ b/src/main/java/com/nonononoki/alovoa/html/LoginResource.java
@@ -18,7 +18,10 @@ public class LoginResource {
@Value("${app.privacy.update-date}")
private String privacyDate;
-
+
+ @Value("${app.captcha.login.enabled}")
+ private String captchaEnabled;
+
public static final String URL = "/login";
@GetMapping(URL)
@@ -30,6 +33,7 @@ public ModelAndView login() throws AlovoaException {
}
ModelAndView mav = new ModelAndView("login");
+ mav.addObject("captchaEnabled", Boolean.valueOf(captchaEnabled));
return mav;
}
}
diff --git a/src/main/java/com/nonononoki/alovoa/html/PasswordResource.java b/src/main/java/com/nonononoki/alovoa/html/PasswordResource.java
index ff2ca606..e00850cd 100644
--- a/src/main/java/com/nonononoki/alovoa/html/PasswordResource.java
+++ b/src/main/java/com/nonononoki/alovoa/html/PasswordResource.java
@@ -7,6 +7,7 @@
import com.nonononoki.alovoa.service.AuthService;
import com.nonononoki.alovoa.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -34,6 +35,9 @@ public class PasswordResource {
@Autowired
private TextEncryptorConverter textEncryptor;
+ @Value("${app.captcha.password.enabled}")
+ private String captchaPasswordEnabled;
+
@GetMapping("/reset")
public ModelAndView passwordReset() throws AlovoaException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException,
@@ -41,6 +45,7 @@ public ModelAndView passwordReset() throws AlovoaException, InvalidKeyException,
ModelAndView mav = new ModelAndView("password-reset");
User user = authService.getCurrentUser();
mav.addObject("user", UserDto.userToUserDto(user, user, userService, textEncryptor, UserDto.NO_MEDIA));
+ mav.addObject("captchaEnabled", Boolean.valueOf(captchaPasswordEnabled));
return mav;
}
diff --git a/src/main/java/com/nonononoki/alovoa/html/RegisterResource.java b/src/main/java/com/nonononoki/alovoa/html/RegisterResource.java
index a3809a21..4694f26c 100644
--- a/src/main/java/com/nonononoki/alovoa/html/RegisterResource.java
+++ b/src/main/java/com/nonononoki/alovoa/html/RegisterResource.java
@@ -1,6 +1,7 @@
package com.nonononoki.alovoa.html;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -27,7 +28,10 @@ public class RegisterResource {
@Autowired
private AuthService authService;
-
+
+ @Value("${app.captcha.register.enabled}")
+ private String captchaRegisterEnabled;
+
public static final String URL = "/register";
@GetMapping(URL)
@@ -40,6 +44,7 @@ public ModelAndView register() throws AlovoaException {
ModelAndView mav = new ModelAndView("register");
mav.addObject("genders", genderRepo.findAll());
mav.addObject("intentions", userIntentionRepo.findAll());
+ mav.addObject("captchaRegisterEnabled", Boolean.parseBoolean(captchaRegisterEnabled));
return mav;
}
diff --git a/src/main/java/com/nonononoki/alovoa/model/RegisterDto.java b/src/main/java/com/nonononoki/alovoa/model/RegisterDto.java
index 0c70e258..ee5d9561 100644
--- a/src/main/java/com/nonononoki/alovoa/model/RegisterDto.java
+++ b/src/main/java/com/nonononoki/alovoa/model/RegisterDto.java
@@ -17,4 +17,7 @@ public class RegisterDto {
private boolean termsConditions;
private boolean privacy;
+
+ private String captchaText;
+ private long captchaId;
}
diff --git a/src/main/java/com/nonononoki/alovoa/service/ImprintService.java b/src/main/java/com/nonononoki/alovoa/service/ImprintService.java
index fad2e414..b22596a3 100644
--- a/src/main/java/com/nonononoki/alovoa/service/ImprintService.java
+++ b/src/main/java/com/nonononoki/alovoa/service/ImprintService.java
@@ -5,6 +5,7 @@
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.nonononoki.alovoa.entity.Contact;
@@ -24,11 +25,16 @@ public class ImprintService {
@Autowired
private ContactRepository contactRepo;
+ @Value("${app.captcha.imprint.enabled}")
+ private String captchaImprintEnabled;
+
public Contact contact(ContactDto dto)
throws UnsupportedEncodingException, NoSuchAlgorithmException, AlovoaException {
- boolean isValid = captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText());
- if (!isValid) {
- throw new AlovoaException(publicService.text("backend.error.captcha.invalid"));
+ if (Boolean.parseBoolean(captchaImprintEnabled)) {
+ boolean isValid = captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText());
+ if (!isValid) {
+ throw new AlovoaException(publicService.text("backend.error.captcha.invalid"));
+ }
}
Contact c = new Contact();
diff --git a/src/main/java/com/nonononoki/alovoa/service/PasswordService.java b/src/main/java/com/nonononoki/alovoa/service/PasswordService.java
index 0eb86352..0f329fe4 100644
--- a/src/main/java/com/nonononoki/alovoa/service/PasswordService.java
+++ b/src/main/java/com/nonononoki/alovoa/service/PasswordService.java
@@ -52,14 +52,19 @@ public class PasswordService {
@Value("${app.user.password-reset.duration.valid}")
private int userPasswordResetDuration;
+ @Value("${app.captcha.password.enabled}")
+ private String captchaPasswordEnabled;
+
public UserPasswordToken resetPassword(PasswordResetDto dto)
throws AlovoaException, NoSuchAlgorithmException, MessagingException, IOException {
User u = authService.getCurrentUser();
if (u == null) {
- if (!captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText())) {
- throw new AlovoaException("captcha_invalid");
+ if (Boolean.parseBoolean(captchaPasswordEnabled)) {
+ if (!captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText())) {
+ throw new AlovoaException("captcha_invalid");
+ }
}
u = userRepo.findByEmail(Tools.cleanEmail(dto.getEmail()));
diff --git a/src/main/java/com/nonononoki/alovoa/service/RegisterService.java b/src/main/java/com/nonononoki/alovoa/service/RegisterService.java
index b5af5ef3..c1d67aff 100644
--- a/src/main/java/com/nonononoki/alovoa/service/RegisterService.java
+++ b/src/main/java/com/nonononoki/alovoa/service/RegisterService.java
@@ -108,6 +108,9 @@ public class RegisterService {
@Autowired
private TextEncryptorConverter textEncryptor;
+ @Value("${app.captcha.register.enabled}")
+ private String captchaRegisterEnabled;
+
private static final int MIN_PASSWORD_SIZE = 7;
private static final Logger logger = LoggerFactory.getLogger(RegisterService.class);
@@ -121,6 +124,13 @@ public String register(RegisterDto dto)
throw new AlovoaException("email_invalid");
}
+ if (Boolean.parseBoolean(captchaRegisterEnabled)) {
+ boolean isValid = captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText());
+ if (!isValid) {
+ throw new AlovoaException(publicService.text("backend.error.captcha.invalid"));
+ }
+ }
+
if (!profile.equals(Tools.DEV)) {
dto.setEmail(Tools.cleanEmail(dto.getEmail()));
if (plusAddressing && dto.getEmail().contains("+")) {
diff --git a/src/main/java/com/nonononoki/alovoa/service/UserService.java b/src/main/java/com/nonononoki/alovoa/service/UserService.java
index 5952d065..5fb31837 100644
--- a/src/main/java/com/nonononoki/alovoa/service/UserService.java
+++ b/src/main/java/com/nonononoki/alovoa/service/UserService.java
@@ -120,6 +120,9 @@ public class UserService {
@Value("${app.intention.delay}")
private long intentionDelay;
+ @Value("${app.captcha.delete.enabled}")
+ private String captchaDeleteEnabled;
+
public static void removeUserDataCascading(User user, UserDeleteParams userDeleteParam) {
UserRepository userRepo = userDeleteParam.getUserRepo();
@@ -329,8 +332,10 @@ public void deleteAccountConfirm(UserDeleteAccountDto dto)
throw new AlovoaException("deletion_wrong_email");
}
- if (!captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText())) {
- throw new AlovoaException("captcha_invalid");
+ if (Boolean.parseBoolean(captchaDeleteEnabled)) {
+ if (!captchaService.isValid(dto.getCaptchaId(), dto.getCaptchaText())) {
+ throw new AlovoaException("captcha_invalid");
+ }
}
UserDeleteParams userDeleteParam = UserDeleteParams.builder().conversationRepo(conversationRepo)
@@ -800,7 +805,7 @@ public boolean hasNewAlert(String lang) throws AlovoaException {
User user = authService.getCurrentUser(true);
// user always check their alerts periodically in the background, so just update
// it here
- if (user != null) {
+ if (user != null && user.getDates()!=null) {
updateUserInfo(user, lang);
return user.getDates().getNotificationDate().after(user.getDates().getNotificationCheckedDate());
} else {
@@ -810,7 +815,7 @@ public boolean hasNewAlert(String lang) throws AlovoaException {
public boolean hasNewMessage() throws AlovoaException {
User user = authService.getCurrentUser(true);
- if (user != null && user.getDates().getMessageDate() != null
+ if (user != null && user.getDates()!=null && user.getDates().getMessageDate() != null
&& user.getDates().getMessageCheckedDate() != null) {
return user.getDates().getMessageDate().after(user.getDates().getMessageCheckedDate());
} else {
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 39f8c22a..1f3d650f 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -2,6 +2,15 @@
spring.profiles.active=test
server.port=${PORT:8080}
+server.forward-headers-strategy=native
+server.tomcat.remote-ip-header=x-forwarded-for
+server.tomcat.protocol-header=x-forwarded-proto
+
+app.captcha.login.enabled=false
+app.captcha.delete.enabled=false
+app.captcha.imprint.enabled=true
+app.captcha.password.enabled=false
+app.captcha.register.enabled=true
#enable to force https for development
#server.ssl.key-store-type=PKCS12
diff --git a/src/main/resources/templates/delete-account.html b/src/main/resources/templates/delete-account.html
index 0f98e379..c954a717 100644
--- a/src/main/resources/templates/delete-account.html
+++ b/src/main/resources/templates/delete-account.html
@@ -38,7 +38,9 @@
-
+