Add: missing create methods in controllers. Fix: SYSTEM token gets the refresh now. Add: CORS. Add: HTTP to core.
This commit is contained in:
@@ -83,7 +83,7 @@
|
||||
<dependency>
|
||||
<groupId>net.miarma</groupId>
|
||||
<artifactId>backlib</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.miarma.backend.core.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins(
|
||||
"http://localhost:3000",
|
||||
"http://localhost:8081",
|
||||
"http://huertos:8081"
|
||||
)
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import net.miarma.backlib.http.RestAuthEntryPoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@@ -15,6 +16,11 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@@ -34,9 +40,23 @@ public class SecurityConfig {
|
||||
this.accessDeniedHandler = accessDeniedHandler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowedOrigins(List.of("http://localhost:3000"));
|
||||
config.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS"));
|
||||
config.setAllowedHeaders(List.of("*"));
|
||||
config.setAllowCredentials(true);
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.cors(Customizer.withDefaults())
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(ex -> ex
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package net.miarma.backend.core.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import net.miarma.backend.core.model.Credential;
|
||||
@@ -106,4 +104,10 @@ public class AuthController {
|
||||
|
||||
return ResponseEntity.ok(Map.of("message", "Password changed successfully"));
|
||||
}
|
||||
|
||||
@GetMapping("/validate")
|
||||
public ResponseEntity<Boolean> validate(@RequestHeader("Authorization") String authHeader) {
|
||||
String token = authHeader.substring(7);
|
||||
return ResponseEntity.ok(jwtService.validateToken(token));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class FileController {
|
||||
|
||||
@PutMapping("/{fileId}")
|
||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
||||
public ResponseEntity<File> update(@PathVariable("file_id") UUID fileId, @RequestBody File file) {
|
||||
public ResponseEntity<File> update(@PathVariable("fileId") UUID fileId, @RequestBody File file) {
|
||||
file.setFileId(fileId);
|
||||
File updated = fileService.update(file);
|
||||
return ResponseEntity.ok(updated);
|
||||
@@ -80,7 +80,7 @@ public class FileController {
|
||||
|
||||
@DeleteMapping("/{fileId}")
|
||||
@PreAuthorize("hasRole('ADMIN') or @fileService.isOwner(#fileId, authentication.principal.userId)")
|
||||
public ResponseEntity<Void> delete(@PathVariable("file_id") UUID fileId, @RequestBody Map<String,String> body) throws IOException {
|
||||
public ResponseEntity<Void> delete(@PathVariable("fileId") UUID fileId, @RequestBody Map<String,String> body) throws IOException {
|
||||
String filePath = body.get("file_path");
|
||||
Files.deleteIfExists(Paths.get(filePath));
|
||||
fileService.delete(fileId);
|
||||
|
||||
@@ -28,7 +28,8 @@ public interface CredentialRepository extends JpaRepository<Credential, byte[]>
|
||||
|
||||
Optional<Credential> findByServiceIdAndEmail(Byte serviceId, String email);
|
||||
|
||||
Optional<Credential> findByUserIdAndServiceId(UUID userId, Byte serviceId);
|
||||
@Query("SELECT c FROM Credential c WHERE c.userIdBin = :userIdBin AND c.serviceId = :serviceId")
|
||||
Optional<Credential> findByUserIdAndServiceId(@Param("userIdBin") byte[] userIdBin, @Param("serviceId") Byte serviceId);
|
||||
|
||||
Optional<Credential> findByUsernameAndServiceId(String username, int serviceId);
|
||||
|
||||
|
||||
@@ -38,16 +38,16 @@ public class CredentialService {
|
||||
|
||||
public Credential create(Credential credential) {
|
||||
if (credential.getUsername() == null || credential.getUsername().isBlank()) {
|
||||
throw new ValidationException("Username cannot be blank");
|
||||
throw new ValidationException("userName", "Username cannot be blank");
|
||||
}
|
||||
if (credential.getEmail() == null || !credential.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
|
||||
throw new ValidationException("Invalid email format");
|
||||
throw new ValidationException("email", "Invalid email format");
|
||||
}
|
||||
if (credential.getPassword() == null || credential.getPassword().length() < 6) {
|
||||
throw new ValidationException("Password must be at least 6 characters");
|
||||
throw new ValidationException("password", "Password must be at least 6 characters");
|
||||
}
|
||||
if (credential.getServiceId() == null || credential.getServiceId() < 0) {
|
||||
throw new ValidationException("ServiceId must be positive");
|
||||
throw new ValidationException("serviceId", "ServiceId must be positive");
|
||||
}
|
||||
|
||||
boolean existsUsername = credentialRepository.existsByUsernameAndServiceId(
|
||||
@@ -90,7 +90,7 @@ public class CredentialService {
|
||||
}
|
||||
|
||||
public Credential getByUserIdAndService(UUID userId, Byte serviceId) {
|
||||
return credentialRepository.findByUserIdAndServiceId(userId, serviceId)
|
||||
return credentialRepository.findByUserIdAndServiceId(UuidUtil.uuidToBin(userId), serviceId)
|
||||
.orElseThrow(() -> new NotFoundException("Credential not found in this site"));
|
||||
}
|
||||
|
||||
@@ -117,13 +117,13 @@ public class CredentialService {
|
||||
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
||||
|
||||
if (dto.getUsername() != null && dto.getUsername().isBlank()) {
|
||||
throw new ValidationException("Username cannot be blank");
|
||||
throw new ValidationException("userName", "Username cannot be blank");
|
||||
}
|
||||
if (dto.getEmail() != null && !dto.getEmail().matches("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$")) {
|
||||
throw new ValidationException("Invalid email format");
|
||||
throw new ValidationException("email", "Invalid email format");
|
||||
}
|
||||
if (dto.getServiceId() != null && dto.getServiceId() < 0) {
|
||||
throw new ValidationException("ServiceId must be positive");
|
||||
throw new ValidationException("serviceId", "ServiceId must be positive");
|
||||
}
|
||||
|
||||
if (dto.getUsername() != null) cred.setUsername(dto.getUsername());
|
||||
@@ -141,7 +141,7 @@ public class CredentialService {
|
||||
.orElseThrow(() -> new NotFoundException("Credential not found"));
|
||||
|
||||
if (!passwordEncoder.matches(request.oldPassword(), cred.getPassword())) {
|
||||
throw new ValidationException("Old password is incorrect");
|
||||
throw new ValidationException("oldPassword", "Old password is incorrect");
|
||||
}
|
||||
|
||||
cred.setPassword(passwordEncoder.encode(request.newPassword()));
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.UUID;
|
||||
import net.miarma.backend.core.mapper.FileMapper;
|
||||
import net.miarma.backlib.dto.FileDto;
|
||||
import net.miarma.backlib.exception.NotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -24,7 +25,9 @@ import net.miarma.backlib.util.UuidUtil;
|
||||
public class FileService {
|
||||
|
||||
private final FileRepository fileRepository;
|
||||
private final String basePath = "/var/www/files";
|
||||
|
||||
@Value("${filesDir}")
|
||||
private String filesDir;
|
||||
|
||||
public FileService(FileRepository fileRepository) {
|
||||
this.fileRepository = fileRepository;
|
||||
@@ -45,7 +48,7 @@ public class FileService {
|
||||
}
|
||||
|
||||
public File create(FileDto.Request dto, byte[] fileBinary) throws IOException {
|
||||
Path dirPath = Paths.get(basePath, String.valueOf(dto.getContext()));
|
||||
Path dirPath = Paths.get(filesDir, String.valueOf(dto.getContext()));
|
||||
if (!Files.exists(dirPath)) {
|
||||
Files.createDirectories(dirPath);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class UserService {
|
||||
|
||||
public User create(UserDto dto) {
|
||||
if(dto.getDisplayName() == null || dto.getDisplayName().isBlank()) {
|
||||
throw new ValidationException("Display name is required");
|
||||
throw new ValidationException("displayName", "Display name is required");
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
|
||||
@@ -16,6 +16,8 @@ logging:
|
||||
org.hibernate.orm.jdbc.bind: TRACE
|
||||
org.springframework.security: DEBUG
|
||||
|
||||
filesDir: "/home/jomaa/.config/miarma-backend/files"
|
||||
|
||||
jwt:
|
||||
private-key-path: /home/jomaa/.config/miarma-backend/private.pem
|
||||
public-key-path: /home/jomaa/.config/miarma-backend/public.pem
|
||||
|
||||
@@ -15,6 +15,8 @@ logging:
|
||||
org.springframework.security: INFO
|
||||
org.hibernate.SQL: WARN
|
||||
|
||||
filesDir: "/files"
|
||||
|
||||
jwt:
|
||||
private-key-path: ${JWT_PRIVATE_KEY}
|
||||
public-key-path: ${JWT_PUBLIC_KEY}
|
||||
|
||||
Reference in New Issue
Block a user