-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathPasswordResetService.java
More file actions
76 lines (62 loc) · 2.6 KB
/
PasswordResetService.java
File metadata and controls
76 lines (62 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.greencode.service;
import com.greencode.entity.PasswordResetToken;
import com.greencode.entity.User;
import com.greencode.repository.PasswordResetTokenRepository;
import com.greencode.repository.UserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.security.SecureRandom;
import java.time.Duration;
import java.time.Instant;
import java.util.Base64;
@Service
public class PasswordResetService {
private final PasswordResetTokenRepository tokenRepo;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final UserService userService;
public PasswordResetService(
PasswordResetTokenRepository tokenRepo,
UserRepository userRepository,
PasswordEncoder passwordEncoder,
UserService userService
) {
this.tokenRepo = tokenRepo;
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.userService = userService;
}
public String requestReset(String email) {
// Security best practice: don’t reveal if user exists.
// If user not found -> still return silently.
User user = userRepository.findByEmail(email).orElse(null);
if (user == null) {
return null;
}
String token = generateToken();
Instant expiresAt = Instant.now().plus(Duration.ofMinutes(30));
tokenRepo.save(new PasswordResetToken(token, expiresAt, user));
return token;
}
public boolean validateToken(String token) {
return tokenRepo.findByToken(token)
.filter(t -> !t.isUsed())
.filter(t -> t.getExpiresAt().isAfter(Instant.now()))
.isPresent();
}
public void confirmReset(String token, String newPassword) {
PasswordResetToken prt = tokenRepo.findByToken(token)
.orElseThrow(() -> new IllegalArgumentException("Invalid token"));
if (prt.isUsed()) throw new IllegalArgumentException("Token already used");
if (prt.getExpiresAt().isBefore(Instant.now())) throw new IllegalArgumentException("Token expired");
String encoded = passwordEncoder.encode(newPassword);
userService.updatePasswordByEmail(prt.getUser().getEmail(), encoded);
prt.setUsed(true);
tokenRepo.save(prt);
}
private String generateToken() {
byte[] bytes = new byte[32];
new SecureRandom().nextBytes(bytes);
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}
}