Skip to content

Commit 9c404fc

Browse files
committed
feat: fix backend issues with state and memory leak
1 parent fa8c84b commit 9c404fc

19 files changed

Lines changed: 80 additions & 95 deletions

docker-compose.dev.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ services:
3939
ports:
4040
- "8585:8585"
4141
- "5005:5005"
42-
image: maven:3.9.9-eclipse-temurin-25
42+
image: maven:3.9.12-eclipse-temurin-25
4343
entrypoint: './mvnw -ntp spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005" -Dmaven.plugin.validation=VERBOSE'
4444
working_dir: /app
4545
volumes:

server/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
<configuration>
174174
<enableLazyInitialization>true</enableLazyInitialization>
175175
<enableDirtyTracking>true</enableDirtyTracking>
176-
<enableAssociationManagement>true</enableAssociationManagement>
176+
<enableAssociationManagement>false</enableAssociationManagement>
177177
</configuration>
178178
</execution>
179179
</executions>

server/src/main/java/br/com/tasknoteapp/server/config/SecurityConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
1515
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
1616
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
17+
import org.springframework.security.config.http.SessionCreationPolicy;
1718
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
1819
import org.springframework.security.crypto.password.PasswordEncoder;
1920
import org.springframework.security.web.SecurityFilterChain;
@@ -59,6 +60,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
5960
.permitAll())
6061
.httpBasic(AbstractHttpConfigurer::disable)
6162
.formLogin(AbstractHttpConfigurer::disable)
63+
.sessionManagement(
64+
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
6265
.exceptionHandling(
6366
exceptionHandling ->
6467
exceptionHandling.authenticationEntryPoint(

server/src/main/java/br/com/tasknoteapp/server/controller/NoteController.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package br.com.tasknoteapp.server.controller;
22

3-
import br.com.tasknoteapp.server.entity.NoteEntity;
43
import br.com.tasknoteapp.server.exception.NoteNotFoundException;
54
import br.com.tasknoteapp.server.request.NotePatchRequest;
65
import br.com.tasknoteapp.server.request.NoteRequest;
@@ -77,8 +76,8 @@ public ResponseEntity<NoteResponse> patchNote(
7776
*/
7877
@PostMapping
7978
public ResponseEntity<NoteResponse> postNotes(@RequestBody @Valid NoteRequest noteRequest) {
80-
NoteEntity createdNote = noteService.createNote(noteRequest);
81-
return ResponseEntity.status(HttpStatus.CREATED).body(NoteResponse.fromEntity(createdNote));
79+
NoteResponse createdNote = noteService.createNote(noteRequest);
80+
return ResponseEntity.status(HttpStatus.CREATED).body(createdNote);
8281
}
8382

8483
/**

server/src/main/java/br/com/tasknoteapp/server/entity/NoteEntity.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import jakarta.persistence.Id;
99
import jakarta.persistence.JoinColumn;
1010
import jakarta.persistence.ManyToOne;
11-
import jakarta.persistence.OneToOne;
1211
import jakarta.persistence.Table;
1312
import java.time.LocalDateTime;
1413

@@ -30,9 +29,6 @@ public class NoteEntity {
3029
@ManyToOne(fetch = FetchType.LAZY)
3130
private UserEntity user;
3231

33-
@OneToOne(mappedBy = "note", fetch = FetchType.LAZY)
34-
private NoteUrlEntity noteUrl;
35-
3632
@Column(name = "tag", nullable = true, length = 30)
3733
private String tag;
3834

@@ -77,14 +73,6 @@ public void setUser(UserEntity user) {
7773
this.user = user;
7874
}
7975

80-
public NoteUrlEntity getNoteUrl() {
81-
return noteUrl;
82-
}
83-
84-
public void setNoteUrl(NoteUrlEntity noteUrl) {
85-
this.noteUrl = noteUrl;
86-
}
87-
8876
public String getTag() {
8977
return tag;
9078
}

server/src/main/java/br/com/tasknoteapp/server/entity/UserEntity.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import jakarta.persistence.GeneratedValue;
66
import jakarta.persistence.GenerationType;
77
import jakarta.persistence.Id;
8-
import jakarta.persistence.OneToMany;
98
import jakarta.persistence.Table;
109
import java.time.LocalDateTime;
1110
import java.util.Collection;
@@ -41,9 +40,6 @@ public class UserEntity implements UserDetails {
4140
@Column(name = "name", length = 20)
4241
private String name;
4342

44-
@OneToMany(mappedBy = "user")
45-
private List<TaskEntity> tasks;
46-
4743
@Column(name = "email_confirmed_at", nullable = true)
4844
private LocalDateTime emailConfirmedAt;
4945

@@ -147,14 +143,6 @@ public void setName(String name) {
147143
this.name = name;
148144
}
149145

150-
public List<TaskEntity> getTasks() {
151-
return tasks;
152-
}
153-
154-
public void setTasks(List<TaskEntity> tasks) {
155-
this.tasks = tasks;
156-
}
157-
158146
public LocalDateTime getEmailConfirmedAt() {
159147
return emailConfirmedAt;
160148
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package br.com.tasknoteapp.server.repository;
22

33
import br.com.tasknoteapp.server.entity.NoteUrlEntity;
4+
import java.util.Optional;
45
import org.springframework.data.jpa.repository.JpaRepository;
56

67
/** This interface represents a note url repository, for database access. */
78
public interface NoteUrlRepository extends JpaRepository<NoteUrlEntity, Long> {
89

10+
Optional<NoteUrlEntity> findByNote_id(Long noteId);
11+
912
void deleteByNote_id(Long noteId);
1013
}

server/src/main/java/br/com/tasknoteapp/server/repository/UserPwdLimitRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public interface UserPwdLimitRepository extends JpaRepository<UserPwdLimitEntity
1212

1313
List<UserPwdLimitEntity> findAllByUser_id(Long userId, Sort sort);
1414

15+
List<UserPwdLimitEntity> findTop3ByUser_idOrderByWhenHappenedDesc(Long userId);
16+
1517
@Modifying
1618
@Query("delete UserPwdLimitEntity u where u.user.id = ?1")
1719
void deleteAllForUser(Long userId);

server/src/main/java/br/com/tasknoteapp/server/response/NoteResponse.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package br.com.tasknoteapp.server.response;
22

33
import br.com.tasknoteapp.server.entity.NoteEntity;
4-
import br.com.tasknoteapp.server.entity.NoteUrlEntity;
54
import br.com.tasknoteapp.server.util.TimeAgoUtil;
6-
import java.util.Objects;
75

86
/** This record represents a task and its urls object to be returned. */
97
public record NoteResponse(
@@ -16,9 +14,7 @@ public record NoteResponse(
1614
* @param entity The NoteEntity source data.
1715
* @return NoteResponse instance with all note data and urls, if any.
1816
*/
19-
public static NoteResponse fromEntity(NoteEntity entity) {
20-
NoteUrlEntity noteUrl = entity.getNoteUrl();
21-
String url = Objects.isNull(noteUrl) ? null : noteUrl.getUrl();
17+
public static NoteResponse fromEntity(NoteEntity entity, String url) {
2218
String timeAgoFmt = TimeAgoUtil.format(entity.getLastUpdate());
2319

2420
return new NoteResponse(

server/src/main/java/br/com/tasknoteapp/server/service/AuthService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636
import org.slf4j.Logger;
3737
import org.slf4j.LoggerFactory;
3838
import org.springframework.core.env.Environment;
39-
import org.springframework.data.domain.Sort;
40-
import org.springframework.data.domain.Sort.Direction;
4139
import org.springframework.security.authentication.AuthenticationManager;
4240
import org.springframework.security.authentication.BadCredentialsException;
4341
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -513,8 +511,10 @@ private Optional<String> getGravatarImageUrl(String email) {
513511
}
514512

515513
private void checkLoginAttemptLimit(Long userId) {
516-
Sort sort = Sort.by(Direction.DESC, "whenHappened");
517-
List<UserPwdLimitEntity> userPwdList = userPwdLimitRepository.findAllByUser_id(userId, sort);
514+
// Fetch only the 3 most recent failed attempts to avoid loading unbounded rows for
515+
// targeted/brute-forced accounts.
516+
List<UserPwdLimitEntity> userPwdList =
517+
userPwdLimitRepository.findTop3ByUser_idOrderByWhenHappenedDesc(userId);
518518

519519
logger.warn("login count attempt for user {}: {}", userId, userPwdList.size());
520520

0 commit comments

Comments
 (0)