mirror of
https://gitlab.com/etc404/software-engineering-project.git
synced 2026-05-10 20:52:58 +00:00
more checks and stuff for verification
This commit is contained in:
@@ -25,6 +25,11 @@ public class EmailController {
|
|||||||
if (emailService.isValidEmail(email) == false) {
|
if (emailService.isValidEmail(email) == false) {
|
||||||
return ResponseEntity.status(429).body("Invalid Email Detected.");
|
return ResponseEntity.status(429).body("Invalid Email Detected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (emailService.isEmailTaken(email)) {
|
||||||
|
return ResponseEntity.status(409).body("An account with this email already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,15 @@ public class UserController {
|
|||||||
List<UserDto> users = userService.getUsersByName(name);
|
List<UserDto> users = userService.getUsersByName(name);
|
||||||
return new ResponseEntity<>(users, HttpStatus.OK);
|
return new ResponseEntity<>(users, HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/check")
|
||||||
|
public ResponseEntity<?> isTaken(@RequestParam String name) {
|
||||||
|
|
||||||
|
if (userService.isUsernameTaken(name)) {
|
||||||
|
return ResponseEntity.status(409).body("An account with this username already exists.");
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
// build get current user REST API
|
// build get current user REST API
|
||||||
@GetMapping("/me")
|
@GetMapping("/me")
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import java.util.Optional;
|
|||||||
public interface UserRepo extends JpaRepository<User, Integer> {
|
public interface UserRepo extends JpaRepository<User, Integer> {
|
||||||
|
|
||||||
Optional<User> findByUsername(String username);
|
Optional<User> findByUsername(String username);
|
||||||
|
|
||||||
|
Optional<User> findByEmail(String Email);
|
||||||
|
|
||||||
List<User> findByUsernameContainingIgnoreCase(String name);
|
List<User> findByUsernameContainingIgnoreCase(String name);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import org.springframework.mail.MailException;
|
|||||||
import org.springframework.mail.SimpleMailMessage;
|
import org.springframework.mail.SimpleMailMessage;
|
||||||
import org.springframework.mail.javamail.JavaMailSender;
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.example.demo.repository.UserRepo;
|
||||||
|
|
||||||
import javax.naming.directory.Attributes;
|
import javax.naming.directory.Attributes;
|
||||||
import javax.naming.directory.DirContext;
|
import javax.naming.directory.DirContext;
|
||||||
import javax.naming.directory.InitialDirContext;
|
import javax.naming.directory.InitialDirContext;
|
||||||
@@ -23,6 +26,9 @@ public class EmailService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OtpStore otpStore;
|
private OtpStore otpStore;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserRepo userRepository;
|
||||||
|
|
||||||
public void sendOtpEmail(String toEmail) {
|
public void sendOtpEmail(String toEmail) {
|
||||||
String otp = OtpUtil.generateOtp(6);
|
String otp = OtpUtil.generateOtp(6);
|
||||||
otpStore.save(toEmail, otp);
|
otpStore.save(toEmail, otp);
|
||||||
@@ -46,11 +52,16 @@ public class EmailService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmailTaken(String email) {
|
||||||
|
return userRepository.findByEmail(email.toLowerCase().trim()).isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isValidEmail(String email) {
|
public boolean isValidEmail(String email) {
|
||||||
if (email == null || email.isBlank()) return false;
|
if (email == null || email.isBlank()) return false;
|
||||||
|
|
||||||
String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
|
String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
|
||||||
if (!email.matches(emailRegex)) return false;
|
if (!email.matches(emailRegex)) return false;
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InternetAddress emailAddr = new InternetAddress(email, true);
|
InternetAddress emailAddr = new InternetAddress(email, true);
|
||||||
|
|||||||
@@ -255,4 +255,9 @@ public class UserServiceImpl implements UserService {
|
|||||||
|
|
||||||
return favoriteRepository.existsById(new FavoriteId(user.getId(), recipeId));
|
return favoriteRepository.existsById(new FavoriteId(user.getId(), recipeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean isUsernameTaken(String username) {
|
||||||
|
return userRepository.findByUsername(username.toLowerCase().trim()).isPresent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,8 @@ import com.example.demo.entity.User;
|
|||||||
|
|
||||||
public interface UserService {
|
public interface UserService {
|
||||||
UserDto convertToDto(User user);
|
UserDto convertToDto(User user);
|
||||||
|
|
||||||
|
Boolean isUsernameTaken(String username);
|
||||||
|
|
||||||
User saveUser(User user);
|
User saveUser(User user);
|
||||||
|
|
||||||
|
|||||||
@@ -87,108 +87,142 @@ function isProfane(str) {
|
|||||||
error.textContent = message;
|
error.textContent = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
const form = document.getElementById("createUserForm");
|
const form = document.getElementById("createUserForm");
|
||||||
const passwordField = document.getElementById("password");
|
const passwordField = document.getElementById("password");
|
||||||
const confirmPasswordField = document.getElementById("confirmPassword");
|
const confirmPasswordField = document.getElementById("confirmPassword");
|
||||||
const passwordError = document.getElementById("passwordError");
|
const usernameField = document.getElementById("username");
|
||||||
|
const emailField = document.getElementById("email");
|
||||||
|
const passwordError = document.getElementById("passwordError");
|
||||||
|
|
||||||
function checkPasswords() {
|
function checkPasswords() {
|
||||||
if (confirmPasswordField.value === "") {
|
if (confirmPasswordField.value === "") {
|
||||||
confirmPasswordField.classList.remove("invalid");
|
confirmPasswordField.classList.remove("invalid");
|
||||||
passwordError.textContent = "Password cannot be blank";
|
passwordError.textContent = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (passwordField.value !== confirmPasswordField.value) {
|
||||||
|
confirmPasswordField.classList.add("invalid");
|
||||||
|
passwordError.textContent = "Passwords do not match.";
|
||||||
|
} else {
|
||||||
|
confirmPasswordField.classList.remove("invalid");
|
||||||
|
passwordError.textContent = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (passwordField.value !== confirmPasswordField.value) {
|
passwordField.addEventListener("input", checkPasswords);
|
||||||
confirmPasswordField.classList.add("invalid");
|
confirmPasswordField.addEventListener("input", checkPasswords);
|
||||||
passwordError.textContent = "Passwords do not match.";
|
|
||||||
} else {
|
|
||||||
confirmPasswordField.classList.remove("invalid");
|
|
||||||
passwordError.textContent = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordField.addEventListener("input", checkPasswords);
|
const csrfToken = () => document.querySelector('meta[name="_csrf"]').getAttribute("content");
|
||||||
confirmPasswordField.addEventListener("input", checkPasswords);
|
const csrfHeader = () => document.querySelector('meta[name="_csrf_header"]').getAttribute("content");
|
||||||
|
|
||||||
form.addEventListener("submit", async function(e) {
|
emailField.addEventListener("blur", async () => {
|
||||||
e.preventDefault();
|
if (!emailField.value) return;
|
||||||
|
const res = await fetch(`/api/email/check?email=${encodeURIComponent(emailField.value)}`,
|
||||||
|
{ method: "POST", headers: { [csrfHeader()]: csrfToken() } });
|
||||||
|
if (!res.ok) showError(emailField, await res.text() || "Email already in use.");
|
||||||
|
else clearError(emailField);
|
||||||
|
});
|
||||||
|
|
||||||
const password = passwordField.value;
|
usernameField.addEventListener("blur", async () => {
|
||||||
const confirmPassword = confirmPasswordField.value;
|
if (!usernameField.value) {
|
||||||
const name = document.getElementById("username").value;
|
clearError(usernameField);
|
||||||
const email = document.getElementById("email").value;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (password !== confirmPassword) {
|
if (isProfane(usernameField.value)) {
|
||||||
confirmPasswordField.classList.add("invalid");
|
showError(usernameField, "Username contains inappropriate language.");
|
||||||
passwordError.textContent = "Passwords do not match.";
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (isProfane(document.getElementById("username").value)) {
|
|
||||||
showError(username, 'Username contains inappropriate language');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
clearError(usernameField);
|
||||||
|
|
||||||
const userData = {
|
const res = await fetch(`/api/users/check?name=${encodeURIComponent(usernameField.value)}`,
|
||||||
username: document.getElementById("username").value,
|
{ method: "POST", headers: { [csrfHeader()]: csrfToken() } });
|
||||||
email: document.getElementById("email").value,
|
|
||||||
hashedpassword: password,
|
|
||||||
role: "ROLE_USER"
|
|
||||||
};
|
|
||||||
|
|
||||||
const csrfToken = document.querySelector('meta[name="_csrf"]').getAttribute('content');
|
if (!res.ok) showError(usernameField, await res.text() || "Username already taken.");
|
||||||
const csrfHeader = document.querySelector('meta[name="_csrf_header"]').getAttribute('content');
|
else clearError(usernameField);
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
form.addEventListener("submit", async function(e) {
|
||||||
const checkResponse = await fetch(`/api/email/check?email=${encodeURIComponent(email)}`, {
|
e.preventDefault();
|
||||||
method: "POST",
|
|
||||||
headers: { [csrfHeader]: csrfToken }
|
[usernameField, emailField, passwordField, confirmPasswordField].forEach(clearError);
|
||||||
});
|
passwordError.textContent = "";
|
||||||
|
|
||||||
if (!checkResponse.ok) {
|
const password = passwordField.value;
|
||||||
const errorText = await checkResponse.text();
|
const confirmPassword = confirmPasswordField.value;
|
||||||
passwordError.style.color = "red";
|
const name = usernameField.value;
|
||||||
passwordError.textContent = errorText || "Invalid Email Detected.";
|
const email = emailField.value;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionStorage.setItem("pendingEmail", email);
|
if (password !== confirmPassword) {
|
||||||
sessionStorage.setItem("pendingUser", JSON.stringify({
|
confirmPasswordField.classList.add("invalid");
|
||||||
username: name,
|
passwordError.textContent = "Passwords do not match.";
|
||||||
email: email,
|
return;
|
||||||
hashedpassword: password,
|
}
|
||||||
role: "ROLE_USER"
|
|
||||||
}));
|
|
||||||
|
|
||||||
const sendResponse = await fetch(`/api/email/send?email=${encodeURIComponent(email)}`, {
|
if (isProfane(name)) {
|
||||||
method: "POST",
|
showError(usernameField, "Username contains inappropriate language.");
|
||||||
headers: { [csrfHeader]: csrfToken }
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
if (!sendResponse.ok) {
|
|
||||||
passwordError.style.color = "red";
|
|
||||||
passwordError.textContent = "Failed to send verification email. Please check your address.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordError.style.color = "green";
|
try {
|
||||||
passwordError.textContent = "Check your email for a verification code...";
|
const headers = { [csrfHeader()]: csrfToken() };
|
||||||
setTimeout(function () {
|
|
||||||
window.location.href = "/verify";
|
|
||||||
}, 1500);
|
|
||||||
|
|
||||||
} catch (error) {
|
const emailRes = await fetch(`/api/email/check?email=${encodeURIComponent(email)}`,
|
||||||
passwordError.style.color = "red";
|
{ method: "POST", headers });
|
||||||
passwordError.textContent = "Could not connect to the server.";
|
if (!emailRes.ok) {
|
||||||
console.error("Request error:", error);
|
passwordError.style.color = "red";
|
||||||
}
|
passwordError.textContent = await emailRes.text() || "Invalid email detected.";
|
||||||
});
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const userRes = await fetch(`/api/users/check?name=${encodeURIComponent(name)}`,
|
||||||
|
{ method: "POST", headers });
|
||||||
|
if (!userRes.ok) {
|
||||||
|
passwordError.style.color = "red";
|
||||||
|
passwordError.textContent = await userRes.text() || "Username already taken.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionStorage.setItem("pendingEmail", email);
|
||||||
|
sessionStorage.setItem("pendingUser", JSON.stringify({
|
||||||
|
username: name, email, hashedpassword: password, role: "ROLE_USER"
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
const sendRes = await fetch(`/api/email/send?email=${encodeURIComponent(email)}`,
|
||||||
|
{ method: "POST", headers });
|
||||||
|
if (!sendRes.ok) {
|
||||||
|
passwordError.style.color = "red";
|
||||||
|
passwordError.textContent = "Failed to send verification email. Please check your address.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordError.style.color = "green";
|
||||||
|
passwordError.textContent = "Check your email for a verification code...";
|
||||||
|
setTimeout(() => { window.location.href = "/verify"; }, 1500);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
passwordError.style.color = "red";
|
||||||
|
passwordError.textContent = "Could not connect to the server.";
|
||||||
|
console.error("Request error:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function showError(input, message) {
|
||||||
|
input.classList.add("invalid");
|
||||||
|
passwordError.style.color = "red";
|
||||||
|
passwordError.textContent = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearError(input) {
|
||||||
|
input.classList.remove("invalid");
|
||||||
|
passwordError.textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user