diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/controller/SignupController.java b/src/main/java/com/skycrate/backend/skycrateBackend/controller/SignupController.java new file mode 100644 index 0000000..e39d5cc --- /dev/null +++ b/src/main/java/com/skycrate/backend/skycrateBackend/controller/SignupController.java @@ -0,0 +1,24 @@ +package com.skycrate.backend.skycrateBackend.controller; + +import com.skycrate.backend.skycrateBackend.dto.SignupRequest; +import com.skycrate.backend.skycrateBackend.service.UserService; +import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/auth") +public class SignupController { + + private final UserService userService; + + public SignupController(UserService userService) { + this.userService = userService; + } + + @PostMapping("/signup") + public ResponseEntity signup(@Valid @RequestBody SignupRequest request) { + userService.registerUser(request); + return ResponseEntity.ok("User registered successfully"); + } +} \ No newline at end of file diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/dto/SignupRequest.java b/src/main/java/com/skycrate/backend/skycrateBackend/dto/SignupRequest.java new file mode 100644 index 0000000..a4faf75 --- /dev/null +++ b/src/main/java/com/skycrate/backend/skycrateBackend/dto/SignupRequest.java @@ -0,0 +1,23 @@ +package com.skycrate.backend.skycrateBackend.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +public class SignupRequest { + + @NotBlank + @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "Username must be alphanumeric only") + private String username; + + @NotBlank + @Email + private String email; + + @NotBlank + @Size(min = 8, message = "Password must be at least 8 characters long") + private String password; + + // Getters and Setters +} \ No newline at end of file diff --git a/src/main/java/com/skycrate/backend/skycrateBackend/services/UserService.java b/src/main/java/com/skycrate/backend/skycrateBackend/services/UserService.java new file mode 100644 index 0000000..d37b517 --- /dev/null +++ b/src/main/java/com/skycrate/backend/skycrateBackend/services/UserService.java @@ -0,0 +1,52 @@ +package com.skycrate.backend.skycrateBackend.services; + +import com.skycrate.backend.skycrateBackend.dto.SignupRequest; +import com.skycrate.backend.skycrateBackend.entity.User; +import com.skycrate.backend.skycrateBackend.repository.UserRepository; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.math.BigInteger; +import java.security.MessageDigest; + +@Service +public class UserService { + + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + public void registerUser(SignupRequest request) { + if (isPasswordPwned(request.getPassword())) { + throw new IllegalArgumentException("Password has been compromised in data breaches."); + } + + User user = new User(); + user.setUsername(request.getUsername()); + user.setEmail(request.getEmail()); + user.setPassword(passwordEncoder.encode(request.getPassword())); + userRepository.save(user); + } + + private boolean isPasswordPwned(String password) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] hash = md.digest(password.getBytes()); + String fullHash = String.format("%040x", new BigInteger(1, hash)).toUpperCase(); + String prefix = fullHash.substring(0, 5); + String suffix = fullHash.substring(5); + + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.getForObject("https://api.pwnedpasswords.com/range/" + prefix, String.class); + + return response != null && response.contains(suffix); + } catch (Exception e) { + return false; // If API fails, allow but log in production + } + } +} \ No newline at end of file