Skip to content

Commit c4b18bd

Browse files
committed
feature: Initial Password reset flow implementation
1 parent ceabd3b commit c4b18bd

File tree

6 files changed

+49
-3
lines changed

6 files changed

+49
-3
lines changed

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public boolean sendMail(String to, String token, String message) {
3030
mimeMessageHelper.setSubject(subject);
3131

3232
// Construct the message with the token link
33-
String resetLink = "http://localhost:8080/lost-password?token=" + token;
33+
String resetLink = "http://localhost:8080/api/users/lost-password/" + token;
3434
String messageWithLink = message + "\n\nReset your password here: " + resetLink;
3535
mimeMessageHelper.setText(messageWithLink, true); // Set HTML to true to allow links
3636

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public interface UserService {
5252

5353
Mono<Void> lostPassword(String userEmail);
5454

55+
Mono<Void> resetLostPassword(String userEmail, String token, String newPassword);
56+
5557
Mono<Boolean> setPassword(String userId, String password);
5658

5759
Mono<UserDetail> buildUserDetail(User user, boolean withoutDynamicGroups);

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,30 @@ public Mono<Void> lostPassword(String userEmail) {
280280
}
281281
user.setPasswordResetToken(HashUtils.hash(token.getBytes()));
282282
user.setPasswordResetTokenExpiry(tokenExpiry);
283-
return Mono.empty();
283+
return repository.save(user).then(Mono.empty());
284+
});
285+
}
286+
287+
@Override
288+
public Mono<Void> resetLostPassword(String userEmail, String token, String newPassword) {
289+
return findByName(userEmail)
290+
.flatMap(user -> {
291+
if (Instant.now().until(user.getPasswordResetTokenExpiry(), ChronoUnit.MINUTES) <= 0) {
292+
return ofError(BizError.LOGIN_EXPIRED, "TOKEN_EXPIRED");
293+
}
294+
295+
if (!StringUtils.equals(HashUtils.hash(token.getBytes()), user.getPasswordResetToken())) {
296+
return ofError(BizError.INVALID_PASSWORD, "INVALID_TOKEN");
297+
}
298+
299+
if (StringUtils.isBlank(newPassword)) {
300+
return ofError(BizError.INVALID_PASSWORD, "PASSWORD_NOT_SET_YET");
301+
}
302+
303+
user.setPassword(encryptionService.encryptPassword(newPassword));
304+
user.setPasswordResetToken(StringUtils.EMPTY);
305+
user.setPasswordResetTokenExpiry(Instant.now());
306+
return repository.save(user).then(Mono.empty());
284307
});
285308
}
286309

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserApiService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ public Mono<Void> lostPassword(String userEmail) {
6969
return userService.lostPassword(userEmail);
7070
}
7171

72+
public Mono<Void> resetLostPassword(String userEmail, String token, String newPassword) {
73+
return userService.resetLostPassword(userEmail, token, newPassword);
74+
}
75+
7276
// ========================== TOKEN OPERATIONS START ==========================
7377

7478
public Mono<Void> saveToken(String userId, String source, String token) {

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ public Mono<ResponseView<Void>> lostPassword(@RequestBody LostPasswordRequest re
155155
.map(ResponseView::success);
156156
}
157157

158+
@Override
159+
public Mono<ResponseView<Void>> resetLostPassword(@PathVariable String token, @RequestBody ResetLostPasswordRequest request) {
160+
if (StringUtils.isBlank(request.userEmail()) || StringUtils.isBlank(token)
161+
|| StringUtils.isBlank(request.newPassword())) {
162+
return ofError(BizError.INVALID_PARAMETER, "INVALID_PARAMETER");
163+
}
164+
165+
return userApiService.resetLostPassword(request.userEmail(), token, request.newPassword())
166+
.map(ResponseView::success);
167+
}
168+
158169
@Override
159170
public Mono<ResponseView<Boolean>> setPassword(@RequestParam String password) {
160171
if (StringUtils.isBlank(password)) {

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserEndpoints.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,10 @@ public interface UserEndpoints
122122
public Mono<ResponseView<String>> resetPassword(@RequestBody ResetPasswordRequest request);
123123

124124
@PostMapping("/lost-password")
125-
public Mono<ResponseView<Void>> lostPassword(@RequestBody LostPasswordRequest userEmail);
125+
public Mono<ResponseView<Void>> lostPassword(@RequestBody LostPasswordRequest request);
126+
127+
@PostMapping("/lost-password/{token}")
128+
public Mono<ResponseView<Void>> resetLostPassword(@PathVariable String token, @RequestBody ResetLostPasswordRequest request);
126129

127130
@Operation(
128131
tags = TAG_USER_PASSWORD_MANAGEMENT,
@@ -157,6 +160,9 @@ public record ResetPasswordRequest(String userId) {
157160
public record LostPasswordRequest(String userEmail) {
158161
}
159162

163+
public record ResetLostPasswordRequest(String userEmail, String newPassword) {
164+
}
165+
160166
public record UpdatePasswordRequest(String oldPassword, String newPassword) {
161167
}
162168

0 commit comments

Comments
 (0)