Harden startup config

This commit is contained in:
2026-04-11 23:10:18 -06:00
parent a7f2fc5b92
commit 62094f2f4f
8 changed files with 36 additions and 28 deletions

View File

@@ -1,7 +1,5 @@
package com.petshop.backend.config;
import com.petshop.backend.entity.User;
import com.petshop.backend.repository.UserRepository;
import com.petshop.backend.security.AppPrincipal;
import com.petshop.backend.service.ActivityLogService;
import jakarta.servlet.FilterChain;
@@ -18,15 +16,13 @@ import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@Order(Ordered.LOWEST_PRECEDENCE - 20)
public class ActivityLoggingFilter extends OncePerRequestFilter {
@Component
@Order(Ordered.LOWEST_PRECEDENCE - 20)
public class ActivityLoggingFilter extends OncePerRequestFilter {
private final UserRepository userRepository;
private final ActivityLogService activityLogService;
public ActivityLoggingFilter(UserRepository userRepository, ActivityLogService activityLogService) {
this.userRepository = userRepository;
public ActivityLoggingFilter(ActivityLogService activityLogService) {
this.activityLogService = activityLogService;
}
@@ -73,12 +69,7 @@ public class ActivityLoggingFilter extends OncePerRequestFilter {
return;
}
User user = userRepository.findById(userId).orElse(null);
if (user == null) {
return;
}
String activity = String.format("%s %s -> %d", request.getMethod(), request.getRequestURI(), response.getStatus());
activityLogService.record(user, activity);
activityLogService.record(userId, activity);
}
}

View File

@@ -1,7 +1,6 @@
package com.petshop.backend.config;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.MigrationVersion;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -38,10 +37,7 @@ public class FlywayContextInitializer implements ApplicationContextInitializer<C
Flyway flyway = Flyway.configure()
.dataSource(url, username, password)
.locations(locations)
.baselineOnMigrate(environment.getProperty("spring.flyway.baseline-on-migrate", Boolean.class, false))
.baselineVersion(MigrationVersion.fromVersion(environment.getProperty("spring.flyway.baseline-version", "1")))
.load();
flyway.repair();
flyway.migrate();
return;
} catch (RuntimeException ex) {

View File

@@ -101,7 +101,7 @@ public class AuthController {
User savedUser = userRepository.save(user);
String token = jwtUtil.generateToken(savedUser);
activityLogService.record(savedUser, "POST /api/v1/auth/register -> 201");
activityLogService.record(savedUser.getId(), "POST /api/v1/auth/register -> 201");
return ResponseEntity.status(HttpStatus.CREATED).body(new RegisterResponse(
savedUser.getId(),
@@ -124,7 +124,7 @@ public class AuthController {
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
String token = jwtUtil.generateToken(user);
activityLogService.record(user, "POST /api/v1/auth/login -> 200");
activityLogService.record(user.getId(), "POST /api/v1/auth/login -> 200");
return ResponseEntity.ok(new LoginResponse(
token,

View File

@@ -4,6 +4,7 @@ import com.petshop.backend.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -23,6 +24,16 @@ public class JwtUtil {
@Value("${jwt.expiration}")
private Long expiration;
@PostConstruct
void validateConfiguration() {
if (secret == null || secret.isBlank()) {
throw new IllegalStateException("JWT_SECRET must be configured");
}
if (secret.getBytes(StandardCharsets.UTF_8).length < 32) {
throw new IllegalStateException("JWT_SECRET must be at least 32 bytes long");
}
}
private SecretKey getSigningKey() {
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}

View File

@@ -28,13 +28,16 @@ public class ActivityLogService {
}
@Transactional
public void record(User user, String activity) {
if (user == null || activity == null || activity.isBlank()) {
public void record(Long userId, String activity) {
if (userId == null || activity == null || activity.isBlank()) {
return;
}
try {
User managedUser = userRepository.findById(user.getId()).orElse(user);
User managedUser = userRepository.findById(userId).orElse(null);
if (managedUser == null) {
return;
}
StoreLocation store = managedUser.getPrimaryStore();
ActivityLog entry = new ActivityLog();
entry.setUser(managedUser);
@@ -50,6 +53,13 @@ public class ActivityLogService {
}
}
public void record(User user, String activity) {
if (user == null) {
return;
}
record(user.getId(), activity);
}
@Transactional(readOnly = true)
public List<ActivityLogResponse> getLogs(int limit) {
return activityLogRepository.findRecent(PageRequest.of(0, limit)).stream().map(this::toResponse).toList();

View File

@@ -0,0 +1,2 @@
jwt:
secret: ${JWT_SECRET:local-development-jwt-secret-change-me-please-123456}

View File

@@ -33,9 +33,7 @@ spring:
open-in-view: false
flyway:
enabled: true
baseline-on-migrate: true
baseline-version: 1
enabled: false
server:
port: ${SERVER_PORT:8080}
@@ -50,7 +48,7 @@ springdoc:
path: /swagger-ui
jwt:
secret: ${JWT_SECRET:change_me_please_make_this_at_least_32_characters_long_for_security}
secret: ${JWT_SECRET}
expiration: ${JWT_EXPIRATION:86400000}
stripe:

View File

@@ -7,7 +7,7 @@ Made by **Group 2**, Shiv, Nikitha, Alex, Harkamal.
## Requirements
- IntelliJ IDEA (Community or Ultimate)
- Java 17+
- Java 25+
- Maven (handled through IntelliJ)
- Docker and Docker Compose (for the local MySQL container)